예제 #1
0
        internal void DecodeClassInterfaceAttribute(AttributeSyntax?nodeOpt, DiagnosticBag diagnostics)
        {
            Debug.Assert(!this.HasErrors);

            TypedConstant ctorArgument = this.CommonConstructorArguments[0];

            Debug.Assert(ctorArgument.Kind == TypedConstantKind.Enum || ctorArgument.Kind == TypedConstantKind.Primitive);

            ClassInterfaceType interfaceType = ctorArgument.Kind == TypedConstantKind.Enum ?
                                               ctorArgument.DecodeValue <ClassInterfaceType>(SpecialType.System_Enum) :
                                               (ClassInterfaceType)ctorArgument.DecodeValue <short>(SpecialType.System_Int16);

            switch (interfaceType)
            {
            case ClassInterfaceType.None:
            case Cci.Constants.ClassInterfaceType_AutoDispatch:
            case Cci.Constants.ClassInterfaceType_AutoDual:
                break;

            default:
                // CS0591: Invalid value for argument to '{0}' attribute
                Location attributeArgumentSyntaxLocation = this.GetAttributeArgumentSyntaxLocation(0, nodeOpt);
                diagnostics.Add(ErrorCode.ERR_InvalidAttributeArgument, attributeArgumentSyntaxLocation, nodeOpt != null ? nodeOpt.GetErrorDisplayName() : "");
                break;
            }
        }
예제 #2
0
 private Attribute(Context cx, AttributeData attributeData, IEntity entity, AttributeKind kind)
     : base(cx, attributeData)
 {
     this.attributeSyntax = attributeData.ApplicationSyntaxReference?.GetSyntax() as AttributeSyntax;
     this.entity          = entity;
     this.kind            = kind;
 }
예제 #3
0
        internal string DecodeGuidAttribute(
            AttributeSyntax?nodeOpt,
            BindingDiagnosticBag diagnostics
            )
        {
            Debug.Assert(!this.HasErrors);

            var guidString = (string?)this.CommonConstructorArguments[0].ValueInternal;

            // Native compiler allows only a specific GUID format: "D" format (32 digits separated by hyphens)
            Guid guid;

            if (!Guid.TryParseExact(guidString, "D", out guid))
            {
                // CS0591: Invalid value for argument to '{0}' attribute
                Location attributeArgumentSyntaxLocation = this.GetAttributeArgumentSyntaxLocation(
                    0,
                    nodeOpt
                    );
                diagnostics.Add(
                    ErrorCode.ERR_InvalidAttributeArgument,
                    attributeArgumentSyntaxLocation,
                    nodeOpt != null ? nodeOpt.GetErrorDisplayName() : ""
                    );
                guidString = String.Empty;
            }

            return(guidString !);
        }
예제 #4
0
        private static Location GetSecurityAttributeActionSyntaxLocation(
            AttributeSyntax?nodeOpt,
            TypedConstant typedValue,
            out object displayString
            )
        {
            if (nodeOpt == null)
            {
                displayString = "";
                return(NoLocation.Singleton);
            }

            var argList = nodeOpt.ArgumentList;

            if (argList == null || argList.Arguments.IsEmpty())
            {
                // Optional SecurityAction parameter with default value.
                displayString = (FormattableString)$"{typedValue.ValueInternal}";
                return(nodeOpt.Location);
            }

            AttributeArgumentSyntax argSyntax = argList.Arguments[0];

            displayString = argSyntax.ToString();
            return(argSyntax.Location);
        }
예제 #5
0
 /// <summary>
 /// Initializes a new instance of the <see cref="TypeParameterData"/> struct.
 /// </summary>
 /// <param name="syntax">Target <see cref="TypeParameterSyntax"/>.</param>
 /// <param name="symbol"><see cref="ITypeParameterSymbol"/> represented by the target <paramref name="syntax"/>.</param>
 /// <param name="semanticModel"><see cref="Microsoft.CodeAnalysis.SemanticModel"/> of the target <paramref name="syntax"/>.</param>
 /// <param name="attribute">Valid <c>Durian.DefaultParamAttribute</c> defined on the target <paramref name="symbol"/>.</param>
 /// <param name="targetType">The <see cref="ITypeSymbol"/> that was specified using the <paramref name="attribute"/>. -or- <see langword="null"/> if <paramref name="attribute"/> is <see langword="null"/> or the type cannot be resolved because of error.</param>
 public TypeParameterData(TypeParameterSyntax syntax, ITypeParameterSymbol symbol, SemanticModel semanticModel, AttributeSyntax?attribute, ITypeSymbol?targetType)
 {
     Syntax        = syntax;
     Symbol        = symbol;
     Attribute     = attribute;
     TargetType    = targetType;
     Parent        = (MemberDeclarationSyntax)syntax.Parent !.Parent !;
     SemanticModel = semanticModel;
 }
예제 #6
0
        private static GameSourceEnum ReadGameSourceEnum(string file)
        {
            var ret = new GameSourceEnum();

            string     code = File.ReadAllText(file);
            SyntaxTree tree = ParseTextFast(code);

            var             d            = GetAttrMarkedItem(tree, SyntaxKind.EnumDeclaration, GenAttributes.FenGenGameEnum);
            var             gameEnum     = (EnumDeclarationSyntax)d.Member;
            AttributeSyntax gameEnumAttr = d.Attribute;

            if (gameEnumAttr.ArgumentList == null || gameEnumAttr.ArgumentList.Arguments.Count == 0)
            {
                ThrowErrorAndTerminate(nameof(GenAttributes.FenGenGameEnum) + " had 0 args");
            }

            ret.GameIndexName = ((LiteralExpressionSyntax)gameEnumAttr.ArgumentList !.Arguments[0].Expression).Token.ValueText;

            ret.Name = gameEnum.Identifier.ToString().Trim();
            for (int i = 0; i < gameEnum.Members.Count; i++)
            {
                var    member     = gameEnum.Members[i];
                string memberName = member.Identifier.ToString();
                ret.GameEnumNames.Add(memberName);
                if (!HasAttribute(member, GenAttributes.FenGenNotAGameType))
                {
                    ret.GameIndexEnumNames.Add(memberName);

                    AttributeSyntax?gameAttr = member
                                               .AttributeLists[0]
                                               .Attributes
                                               .FirstOrDefault(x => x.Name.ToString() == GenAttributes.FenGenGame);

                    if (gameAttr != null)
                    {
                        if (gameAttr.ArgumentList == null || gameAttr.ArgumentList.Arguments.Count < 2)
                        {
                            ThrowErrorAndTerminate(nameof(GenAttributes.FenGenGame) + " had < 2 args");
                        }

                        string prefixArg =
                            ((LiteralExpressionSyntax)gameAttr.ArgumentList !.Arguments[0].Expression).Token
                            .ValueText;
                        string steamIdArg =
                            ((LiteralExpressionSyntax)gameAttr.ArgumentList !.Arguments[1].Expression).Token
                            .ValueText;

                        ret.GamePrefixes.Add(prefixArg);
                        ret.SteamIds.Add(steamIdArg);
                    }
                }
            }

            return(ret);
        }
예제 #7
0
파일: SyntaxParser.cs 프로젝트: polsys/cle
        private bool TryParseAttribute([NotNullWhen(true)] out AttributeSyntax?attribute)
        {
            attribute = null;

            // Eat the '['
            var startPosition = EatAndAssertToken(TokenType.OpenBracket);

            // Read the attribute name
            if (!ExpectIdentifier(DiagnosticCode.ExpectedAttributeName, out var attributeName))
            {
                return(false);
            }

            // Read the parameter list, if one is given
            var parameterExpressions = ImmutableList <ExpressionSyntax> .Empty;

            if (_lexer.PeekTokenType() == TokenType.OpenParen && !TryParseParameterList(out parameterExpressions))
            {
                return(false);
            }

            // Assert that each parameter is a literal.
            // This is done in order to simplify attribute resolution: no need to evaluate constants
            // before evaluating attributes.
            // TODO PERF: When replacing the immutable list data structure, add size hinting here
            var parameterLiterals = ImmutableList <LiteralSyntax> .Empty;

            foreach (var paramExpr in parameterExpressions)
            {
                if (paramExpr is LiteralSyntax literal)
                {
                    parameterLiterals = parameterLiterals.Add(literal);
                }
                else
                {
                    _diagnosticSink.Add(DiagnosticCode.AttributeParameterMustBeLiteral, paramExpr.Position);
                    return(false);
                }
            }

            // Eat the closing bracket
            if (!ExpectToken(TokenType.CloseBracket, DiagnosticCode.ExpectedClosingBracket))
            {
                return(false);
            }

            attribute = new AttributeSyntax(attributeName, parameterLiterals, startPosition);
            return(true);
        }
예제 #8
0
        private string?DecodePermissionSetAttribute(CSharpCompilation compilation, AttributeSyntax?nodeOpt, DiagnosticBag diagnostics)
        {
            Debug.Assert(!this.HasErrors);

            string?resolvedFilePath = null;
            var    namedArgs        = this.CommonNamedArguments;

            if (namedArgs.Length == 1)
            {
                var namedArg = namedArgs[0];
                Debug.Assert(AttributeClass is object);
                NamedTypeSymbol attrType     = this.AttributeClass;
                string          filePropName = PermissionSetAttributeWithFileReference.FilePropertyName;
                string          hexPropName  = PermissionSetAttributeWithFileReference.HexPropertyName;

                if (namedArg.Key == filePropName &&
                    PermissionSetAttributeTypeHasRequiredProperty(attrType, filePropName))
                {
                    // resolve file prop path
                    var fileName = (string)namedArg.Value.ValueInternal;
                    var resolver = compilation.Options.XmlReferenceResolver;

                    resolvedFilePath = (resolver != null) ? resolver.ResolveReference(fileName, baseFilePath: null) : null;

                    if (resolvedFilePath == null)
                    {
                        // CS7053: Unable to resolve file path '{0}' specified for the named argument '{1}' for PermissionSet attribute
                        Location argSyntaxLocation = nodeOpt != null?nodeOpt.GetNamedArgumentSyntax(filePropName).Location : NoLocation.Singleton;

                        diagnostics.Add(ErrorCode.ERR_PermissionSetAttributeInvalidFile, argSyntaxLocation, fileName ?? "<null>", filePropName);
                    }
                    else if (!PermissionSetAttributeTypeHasRequiredProperty(attrType, hexPropName))
                    {
                        // PermissionSetAttribute was defined in user source, but doesn't have the required Hex property.
                        // Native compiler still emits the file content as named assignment to 'Hex' property, but this leads to a runtime exception.
                        // We instead skip the fixup and emit the file property.

                        // CONSIDER: We may want to consider taking a breaking change and generating an error here.

                        return(null);
                    }
                }
            }

            return(resolvedFilePath);
        }
예제 #9
0
        GetAttrMarkedItem(SyntaxTree tree, SyntaxKind syntaxKind, string attrName)
        {
            var             attrMarkedItems = new List <MemberDeclarationSyntax>();
            AttributeSyntax?retAttr         = null;

            var nodes = tree.GetCompilationUnitRoot().DescendantNodesAndSelf();

            foreach (SyntaxNode n in nodes)
            {
                if (!n.IsKind(syntaxKind))
                {
                    continue;
                }

                var item = (MemberDeclarationSyntax)n;
                if (item.AttributeLists.Count > 0 && item.AttributeLists[0].Attributes.Count > 0)
                {
                    foreach (var attr in item.AttributeLists[0].Attributes)
                    {
                        if (GetAttributeName(attr.Name.ToString(), attrName))
                        {
                            attrMarkedItems.Add(item);
                            retAttr = attr;
                        }
                    }
                }
            }

            if (attrMarkedItems.Count > 1)
            {
                ThrowErrorAndTerminate("Multiple uses of attribute '" + attrName + "'.");
            }
            else if (attrMarkedItems.Count == 0)
            {
                ThrowErrorAndTerminate("No uses of attribute '" + attrName + "'.");
            }

            return(attrMarkedItems[0], retAttr !);
        }
예제 #10
0
        internal static Location GetAttributeArgumentSyntaxLocation(this AttributeData attribute, int parameterIndex, AttributeSyntax?attributeSyntaxOpt)
        {
            if (attributeSyntaxOpt == null)
            {
                return(NoLocation.Singleton);
            }

            Debug.Assert(attribute is SourceAttributeData);
            return(((SourceAttributeData)attribute).GetAttributeArgumentSyntax(parameterIndex, attributeSyntaxOpt).Location);
        }
예제 #11
0
        private DeclarativeSecurityAction DecodeSecurityAction(TypedConstant typedValue, Symbol targetSymbol, AttributeSyntax?nodeOpt, DiagnosticBag diagnostics, out bool hasErrors)
        {
            Debug.Assert((object)targetSymbol != null);
            Debug.Assert(targetSymbol.Kind == SymbolKind.Assembly || targetSymbol.Kind == SymbolKind.NamedType || targetSymbol.Kind == SymbolKind.Method);

            int  securityAction = (int)typedValue.ValueInternal;
            bool isPermissionRequestAction;

            switch (securityAction)
            {
            case (int)DeclarativeSecurityAction.InheritanceDemand:
            case (int)DeclarativeSecurityAction.LinkDemand:
                if (this.IsTargetAttribute(targetSymbol, AttributeDescription.PrincipalPermissionAttribute))
                {
                    // CS7052: SecurityAction value '{0}' is invalid for PrincipalPermission attribute
                    object   displayString;
                    Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString);
                    diagnostics.Add(ErrorCode.ERR_PrincipalPermissionInvalidAction, syntaxLocation, displayString);
                    hasErrors = true;
                    return(DeclarativeSecurityAction.None);
                }

                isPermissionRequestAction = false;
                break;

            case 1:
            // Native compiler allows security action value 1 for security attributes on types/methods, even though there is no corresponding field in System.Security.Permissions.SecurityAction enum.
            // We will maintain compatibility.

            case (int)DeclarativeSecurityAction.Assert:
            case (int)DeclarativeSecurityAction.Demand:
            case (int)DeclarativeSecurityAction.PermitOnly:
            case (int)DeclarativeSecurityAction.Deny:
                isPermissionRequestAction = false;
                break;

            case (int)DeclarativeSecurityAction.RequestMinimum:
            case (int)DeclarativeSecurityAction.RequestOptional:
            case (int)DeclarativeSecurityAction.RequestRefuse:
                isPermissionRequestAction = true;
                break;

            default:
            {
                // CS7049: Security attribute '{0}' has an invalid SecurityAction value '{1}'
                object   displayString;
                Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString);
                diagnostics.Add(ErrorCode.ERR_SecurityAttributeInvalidAction, syntaxLocation, nodeOpt != null ? nodeOpt.GetErrorDisplayName() : "", displayString);
                hasErrors = true;
                return(DeclarativeSecurityAction.None);
            }
            }

            // Validate security action for symbol kind
            if (isPermissionRequestAction)
            {
                if (targetSymbol.Kind == SymbolKind.NamedType || targetSymbol.Kind == SymbolKind.Method)
                {
                    // Types and methods cannot take permission requests.

                    // CS7051: SecurityAction value '{0}' is invalid for security attributes applied to a type or a method
                    object   displayString;
                    Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString);
                    diagnostics.Add(ErrorCode.ERR_SecurityAttributeInvalidActionTypeOrMethod, syntaxLocation, displayString);
                    hasErrors = true;
                    return(DeclarativeSecurityAction.None);
                }
            }
            else
            {
                if (targetSymbol.Kind == SymbolKind.Assembly)
                {
                    // Assemblies cannot take declarative security.

                    // CS7050: SecurityAction value '{0}' is invalid for security attributes applied to an assembly
                    object   displayString;
                    Location syntaxLocation = GetSecurityAttributeActionSyntaxLocation(nodeOpt, typedValue, out displayString);
                    diagnostics.Add(ErrorCode.ERR_SecurityAttributeInvalidActionAssembly, syntaxLocation, displayString);
                    hasErrors = true;
                    return(DeclarativeSecurityAction.None);
                }
            }

            hasErrors = false;
            return((DeclarativeSecurityAction)securityAction);
        }
예제 #12
0
        private DeclarativeSecurityAction DecodeSecurityAttributeAction(Symbol targetSymbol, CSharpCompilation compilation, AttributeSyntax?nodeOpt, out bool hasErrors, DiagnosticBag diagnostics)
        {
            Debug.Assert((object)targetSymbol != null);
            Debug.Assert(targetSymbol.Kind == SymbolKind.Assembly || targetSymbol.Kind == SymbolKind.NamedType || targetSymbol.Kind == SymbolKind.Method);
            Debug.Assert(this.IsSecurityAttribute(compilation));

            var ctorArgs = this.CommonConstructorArguments;

            if (!ctorArgs.Any())
            {
                // NOTE:    Security custom attributes must have a valid SecurityAction as its first argument, we have none here.
                // NOTE:    Ideally, we should always generate 'CS7048: First argument to a security attribute must be a valid SecurityAction' for this case.
                // NOTE:    However, native compiler allows applying System.Security.Permissions.HostProtectionAttribute attribute without any argument and uses
                // NOTE:    SecurityAction.LinkDemand as the default SecurityAction in this case. We maintain compatibility with the native compiler for this case.

                // BREAKING CHANGE: Even though the native compiler intends to allow only HostProtectionAttribute to be applied without any arguments,
                //                  it doesn't quite do this correctly

                // The implementation issue leads to the native compiler allowing any user defined security attribute with a parameterless constructor and a named property argument as the first
                // attribute argument to have the above mentioned behavior, even though the comment clearly mentions that this behavior was intended only for the HostProtectionAttribute.
                // We currently allow this case only for the HostProtectionAttribute. In future if need arises, we can exactly match native compiler's behavior.

                if (this.IsTargetAttribute(targetSymbol, AttributeDescription.HostProtectionAttribute))
                {
                    hasErrors = false;
                    return(DeclarativeSecurityAction.LinkDemand);
                }
            }
            else
            {
                TypedConstant firstArg     = ctorArgs.First();
                TypeSymbol    firstArgType = (TypeSymbol)firstArg.TypeInternal;
                if ((object)firstArgType != null && firstArgType.Equals(compilation.GetWellKnownType(WellKnownType.System_Security_Permissions_SecurityAction)))
                {
                    return(DecodeSecurityAction(firstArg, targetSymbol, nodeOpt, diagnostics, out hasErrors));
                }
            }

            // CS7048: First argument to a security attribute must be a valid SecurityAction
            diagnostics.Add(ErrorCode.ERR_SecurityAttributeMissingAction, nodeOpt != null ? nodeOpt.Name.Location : NoLocation.Singleton);
            hasErrors = true;
            return(DeclarativeSecurityAction.None);
        }
        private async Task <Document> ConvertToAsyncPackageAsync(CodeFixContext context, Diagnostic diagnostic, CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await context.Document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            Compilation?compilation = await context.Document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

            Assumes.NotNull(compilation);
            SyntaxNode root = await context.Document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            BaseTypeSyntax          baseTypeSyntax         = root.FindNode(diagnostic.Location.SourceSpan).FirstAncestorOrSelf <BaseTypeSyntax>();
            ClassDeclarationSyntax  classDeclarationSyntax = baseTypeSyntax.FirstAncestorOrSelf <ClassDeclarationSyntax>();
            MethodDeclarationSyntax initializeMethodSyntax = classDeclarationSyntax.DescendantNodes()
                                                             .OfType <MethodDeclarationSyntax>()
                                                             .FirstOrDefault(method => method.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.OverrideKeyword)) && method.Identifier.Text == Types.Package.Initialize);
            InvocationExpressionSyntax?baseInitializeInvocationSyntax = initializeMethodSyntax?.Body?.DescendantNodes()
                                                                        .OfType <InvocationExpressionSyntax>()
                                                                        .FirstOrDefault(ies => ies.Expression is MemberAccessExpressionSyntax memberAccess && memberAccess.Name?.Identifier.Text == Types.Package.Initialize && memberAccess.Expression is BaseExpressionSyntax);
            var             getServiceInvocationsSyntax = new List <InvocationExpressionSyntax>();
            AttributeSyntax?packageRegistrationSyntax   = null;

            {
                INamedTypeSymbol userClassSymbol             = semanticModel.GetDeclaredSymbol(classDeclarationSyntax, context.CancellationToken);
                INamedTypeSymbol packageRegistrationType     = compilation.GetTypeByMetadataName(Types.PackageRegistrationAttribute.FullName);
                AttributeData?   packageRegistrationInstance = userClassSymbol?.GetAttributes().FirstOrDefault(a => Equals(a.AttributeClass, packageRegistrationType));
                if (packageRegistrationInstance?.ApplicationSyntaxReference != null)
                {
                    packageRegistrationSyntax = (AttributeSyntax)await packageRegistrationInstance.ApplicationSyntaxReference.GetSyntaxAsync(cancellationToken).ConfigureAwait(false);
                }
            }

            if (initializeMethodSyntax != null)
            {
                getServiceInvocationsSyntax.AddRange(
                    from invocation in initializeMethodSyntax.DescendantNodes().OfType <InvocationExpressionSyntax>()
                    let memberBinding = invocation.Expression as MemberAccessExpressionSyntax
                                        let identifierName = invocation.Expression as IdentifierNameSyntax
                                                             where identifierName?.Identifier.Text == Types.Package.GetService ||
                                                             (memberBinding.Name.Identifier.Text == Types.Package.GetService && memberBinding.Expression.IsKind(SyntaxKind.ThisExpression))
                                                             select invocation);
            }

            // Make it easier to track nodes across changes.
            var nodesToTrack = new List <SyntaxNode?>
            {
                baseTypeSyntax,
                initializeMethodSyntax,
                baseInitializeInvocationSyntax,
                packageRegistrationSyntax,
            };

            nodesToTrack.AddRange(getServiceInvocationsSyntax);
            nodesToTrack.RemoveAll(n => n == null);
            SyntaxNode updatedRoot = root.TrackNodes(nodesToTrack);

            // Replace the Package base type with AsyncPackage
            baseTypeSyntax = updatedRoot.GetCurrentNode(baseTypeSyntax);
            SimpleBaseTypeSyntax asyncPackageBaseTypeSyntax = SyntaxFactory.SimpleBaseType(Types.AsyncPackage.TypeSyntax.WithAdditionalAnnotations(Simplifier.Annotation))
                                                              .WithLeadingTrivia(baseTypeSyntax.GetLeadingTrivia())
                                                              .WithTrailingTrivia(baseTypeSyntax.GetTrailingTrivia());

            updatedRoot = updatedRoot.ReplaceNode(baseTypeSyntax, asyncPackageBaseTypeSyntax);

            // Update the PackageRegistration attribute
            if (packageRegistrationSyntax != null)
            {
                LiteralExpressionSyntax trueExpression = SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression);
                packageRegistrationSyntax = updatedRoot.GetCurrentNode(packageRegistrationSyntax);
                AttributeArgumentSyntax allowsBackgroundLoadingSyntax = packageRegistrationSyntax.ArgumentList.Arguments.FirstOrDefault(a => a.NameEquals?.Name?.Identifier.Text == Types.PackageRegistrationAttribute.AllowsBackgroundLoading);
                if (allowsBackgroundLoadingSyntax != null)
                {
                    updatedRoot = updatedRoot.ReplaceNode(
                        allowsBackgroundLoadingSyntax,
                        allowsBackgroundLoadingSyntax.WithExpression(trueExpression));
                }
                else
                {
                    updatedRoot = updatedRoot.ReplaceNode(
                        packageRegistrationSyntax,
                        packageRegistrationSyntax.AddArgumentListArguments(
                            SyntaxFactory.AttributeArgument(trueExpression).WithNameEquals(SyntaxFactory.NameEquals(Types.PackageRegistrationAttribute.AllowsBackgroundLoading))));
                }
            }

            // Find the Initialize override, if present, and update it to InitializeAsync
            if (initializeMethodSyntax != null)
            {
                IdentifierNameSyntax cancellationTokenLocalVarName = SyntaxFactory.IdentifierName("cancellationToken");
                IdentifierNameSyntax progressLocalVarName          = SyntaxFactory.IdentifierName("progress");
                initializeMethodSyntax = updatedRoot.GetCurrentNode(initializeMethodSyntax);
                BlockSyntax newBody = initializeMethodSyntax.Body;

                SyntaxTriviaList leadingTrivia = SyntaxFactory.TriviaList(
                    SyntaxFactory.Comment(@"// When initialized asynchronously, we *may* be on a background thread at this point."),
                    SyntaxFactory.CarriageReturnLineFeed,
                    SyntaxFactory.Comment(@"// Do any initialization that requires the UI thread after switching to the UI thread."),
                    SyntaxFactory.CarriageReturnLineFeed,
                    SyntaxFactory.Comment(@"// Otherwise, remove the switch to the UI thread if you don't need it."),
                    SyntaxFactory.CarriageReturnLineFeed);

                ExpressionStatementSyntax switchToMainThreadStatement = SyntaxFactory.ExpressionStatement(
                    SyntaxFactory.AwaitExpression(
                        SyntaxFactory.InvocationExpression(
                            SyntaxFactory.MemberAccessExpression(
                                SyntaxKind.SimpleMemberAccessExpression,
                                SyntaxFactory.MemberAccessExpression(
                                    SyntaxKind.SimpleMemberAccessExpression,
                                    SyntaxFactory.ThisExpression(),
                                    SyntaxFactory.IdentifierName(Types.ThreadHelper.JoinableTaskFactory)),
                                SyntaxFactory.IdentifierName(Types.JoinableTaskFactory.SwitchToMainThreadAsync)))
                        .AddArgumentListArguments(SyntaxFactory.Argument(cancellationTokenLocalVarName))))
                                                                        .WithLeadingTrivia(leadingTrivia)
                                                                        .WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed);

                if (baseInitializeInvocationSyntax != null)
                {
                    var baseInitializeAsyncInvocationBookmark = new SyntaxAnnotation();
                    AwaitExpressionSyntax baseInitializeAsyncInvocationSyntax = SyntaxFactory.AwaitExpression(
                        baseInitializeInvocationSyntax
                        .WithLeadingTrivia()
                        .WithExpression(
                            SyntaxFactory.MemberAccessExpression(
                                SyntaxKind.SimpleMemberAccessExpression,
                                SyntaxFactory.BaseExpression(),
                                SyntaxFactory.IdentifierName(Types.AsyncPackage.InitializeAsync)))
                        .AddArgumentListArguments(
                            SyntaxFactory.Argument(cancellationTokenLocalVarName),
                            SyntaxFactory.Argument(progressLocalVarName)))
                                                                                .WithLeadingTrivia(baseInitializeInvocationSyntax.GetLeadingTrivia())
                                                                                .WithAdditionalAnnotations(baseInitializeAsyncInvocationBookmark);
                    newBody = newBody.ReplaceNode(initializeMethodSyntax.GetCurrentNode(baseInitializeInvocationSyntax), baseInitializeAsyncInvocationSyntax);
                    StatementSyntax baseInvocationStatement = newBody.GetAnnotatedNodes(baseInitializeAsyncInvocationBookmark).First().FirstAncestorOrSelf <StatementSyntax>();

                    newBody = newBody.InsertNodesAfter(
                        baseInvocationStatement,
                        new[] { switchToMainThreadStatement.WithLeadingTrivia(switchToMainThreadStatement.GetLeadingTrivia().Insert(0, SyntaxFactory.LineFeed)) });
                }
                else
                {
                    newBody = newBody.WithStatements(
                        newBody.Statements.Insert(0, switchToMainThreadStatement));
                }

                MethodDeclarationSyntax initializeAsyncMethodSyntax = initializeMethodSyntax
                                                                      .WithIdentifier(SyntaxFactory.Identifier(Types.AsyncPackage.InitializeAsync))
                                                                      .WithReturnType(Types.Task.TypeSyntax.WithAdditionalAnnotations(Simplifier.Annotation))
                                                                      .AddModifiers(SyntaxFactory.Token(SyntaxKind.AsyncKeyword))
                                                                      .AddParameterListParameters(
                    SyntaxFactory.Parameter(cancellationTokenLocalVarName.Identifier).WithType(Types.CancellationToken.TypeSyntax.WithAdditionalAnnotations(Simplifier.Annotation)),
                    SyntaxFactory.Parameter(progressLocalVarName.Identifier).WithType(Types.IProgress.TypeSyntaxOf(Types.ServiceProgressData.TypeSyntax).WithAdditionalAnnotations(Simplifier.Annotation)))
                                                                      .WithBody(newBody);
                updatedRoot = updatedRoot.ReplaceNode(initializeMethodSyntax, initializeAsyncMethodSyntax);

                // Replace GetService calls with GetServiceAsync
                getServiceInvocationsSyntax = updatedRoot.GetCurrentNodes <InvocationExpressionSyntax>(getServiceInvocationsSyntax).ToList();
                updatedRoot = updatedRoot.ReplaceNodes(
                    getServiceInvocationsSyntax,
                    (orig, node) =>
                {
                    InvocationExpressionSyntax invocation = node;
                    if (invocation.Expression is IdentifierNameSyntax methodName)
                    {
                        invocation = invocation.WithExpression(SyntaxFactory.IdentifierName(Types.AsyncPackage.GetServiceAsync));
                    }
                    else if (invocation.Expression is MemberAccessExpressionSyntax memberAccess)
                    {
                        invocation = invocation.WithExpression(
                            memberAccess.WithName(SyntaxFactory.IdentifierName(Types.AsyncPackage.GetServiceAsync)));
                    }

                    return(SyntaxFactory.ParenthesizedExpression(SyntaxFactory.AwaitExpression(invocation))
                           .WithAdditionalAnnotations(Simplifier.Annotation));
                });

                updatedRoot = await Utils.AddUsingTaskEqualsDirectiveAsync(updatedRoot, cancellationToken);
            }

            Document newDocument = context.Document.WithSyntaxRoot(updatedRoot);

            newDocument = await ImportAdder.AddImportsAsync(newDocument, Simplifier.Annotation, cancellationToken : cancellationToken);

            return(newDocument);
        }
예제 #14
0
        /// <summary>
        /// Try find an attribute of the expected type.
        /// </summary>
        /// <param name="declaration">The <see cref="FieldDeclarationSyntax"/>.</param>
        /// <param name="expected">The expected type.</param>
        /// <param name="semanticModel">The <see cref="SemanticModel"/>.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
        /// <param name="result">The match.</param>
        /// <returns>True if an attribute of the expected type was found.</returns>
        public static bool TryFind(FieldDeclarationSyntax declaration, QualifiedType expected, SemanticModel semanticModel, CancellationToken cancellationToken, [NotNullWhen(true)] out AttributeSyntax?result)
        {
            if (declaration is null)
            {
                throw new ArgumentNullException(nameof(declaration));
            }

            if (expected is null)
            {
                throw new ArgumentNullException(nameof(expected));
            }

            if (semanticModel is null)
            {
                throw new ArgumentNullException(nameof(semanticModel));
            }

            return(TryFind(declaration.AttributeLists, expected, semanticModel, cancellationToken, out result));
        }
예제 #15
0
        /// <summary>
        /// Try find an attribute of the expected type.
        /// </summary>
        /// <param name="attributeLists">The <see cref="SyntaxList{AttributeListSyntax}"/>.</param>
        /// <param name="expected">The expected type.</param>
        /// <param name="semanticModel">The <see cref="SemanticModel"/>.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
        /// <param name="result">The match.</param>
        /// <returns>True if an attribute of the expected type was found.</returns>
        public static bool TryFind(this SyntaxList <AttributeListSyntax> attributeLists, QualifiedType expected, SemanticModel semanticModel, CancellationToken cancellationToken, [NotNullWhen(true)] out AttributeSyntax?result)
        {
            result = null;
            foreach (var attributeList in attributeLists)
            {
                foreach (var attribute in attributeList.Attributes)
                {
                    if (semanticModel.TryGetNamedType(attribute, expected, cancellationToken, out _))
                    {
                        result = attribute;
                        return(true);
                    }
                }
            }

            return(false);
        }