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; } }
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; }
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 !); }
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); }
/// <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; }
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); }
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); }
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); }
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 !); }
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); }
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); }
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); }
/// <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)); }
/// <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); }