public override ExpressionSyntax VisitMemberAccessExpression(MemberAccessExpressionSyntax node) { node = node.WithExpression(Visit(node.Expression)); var parentIndentWidth = node .GetLeadingTrivia() .FirstOrDefault(x => x.IsKind(SyntaxKind.WhitespaceTrivia)) .Span .Length; if (!node.Expression.GetTrailingTrivia().Any(x => x.IsKind(SyntaxKind.EndOfLineTrivia))) { node = node.WithExpression( node.Expression.WithTrailingTrivia( new[] { SyntaxFactory.EndOfLine("\n") })); } var oldWhitespaceTrivia = node.OperatorToken.LeadingTrivia.FirstOrDefault(x => x.IsKind(SyntaxKind.WhitespaceTrivia)); if (oldWhitespaceTrivia.Span.Length != parentIndentWidth + 4) { var newWhitespaceTrivia = SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, new string(' ', parentIndentWidth + 4)); node = node .WithOperatorToken( node.OperatorToken.WithLeadingTrivia(newWhitespaceTrivia)); } return(node); }
SyntaxNode GetMemberAccessWithoutThis(MemberAccessExpressionSyntax thisItemAsMemberAccessException) { var thisItemAsMemberAccessExceptionSymbol = semanticModel.GetSymbolInfo(thisItemAsMemberAccessException).Symbol; if (thisItemAsMemberAccessExceptionSymbol is IFieldSymbol && !CheckOption((int)RemoveExtraThisKeyword.CleanupTypes.Remove_From_Fields_Call)) { return(null); } if (thisItemAsMemberAccessExceptionSymbol is IPropertySymbol && !CheckOption((int)RemoveExtraThisKeyword.CleanupTypes.Remove_From_Properties_Call)) { return(null); } if (thisItemAsMemberAccessExceptionSymbol is IMethodSymbol && !CheckOption((int)RemoveExtraThisKeyword.CleanupTypes.Remove_From_Method_Call)) { return(null); } var right = thisItemAsMemberAccessException.Name; var symbols = semanticModel.LookupSymbols(thisItemAsMemberAccessException.SpanStart, name: right.Identifier.ValueText); if (symbols.Any(x => x == thisItemAsMemberAccessExceptionSymbol)) { return(right.WithLeadingTrivia(thisItemAsMemberAccessException.GetLeadingTrivia())); } return(null); }
private async Task<Document> InsertAsyncCall(Document document, MemberAccessExpressionSyntax memberAccess, CancellationToken cancellationToken) { var name = memberAccess.Name.Identifier.ValueText; ExpressionSyntax oldNode, newNode, newMemberAccess; switch (name) { case "WaitAny": newMemberAccess = memberAccess.WithName((SimpleNameSyntax)SyntaxFactory.ParseName("WhenAny")); break; case "WaitAll": newMemberAccess = memberAccess.WithName((SimpleNameSyntax)SyntaxFactory.ParseName("WhenAny")); break; case "Wait": newMemberAccess = memberAccess.Expression; break; case "Result": newMemberAccess = memberAccess.Expression; break; case "Sleep": newMemberAccess = SyntaxFactory.ParseExpression("Task.Delay"); break; default: newMemberAccess = memberAccess.WithName((SimpleNameSyntax)SyntaxFactory.ParseName(memberAccess.Name.Identifier.ValueText + "Async")); break; } var invoc = memberAccess.Parent as InvocationExpressionSyntax; // WaitAny, WaitAll, Wait, Sleep, XyzAsync etc. if (invoc != null) { oldNode = invoc; newNode = name == "Wait" ? newMemberAccess : invoc.WithExpression(newMemberAccess); } // t.Result else { oldNode = memberAccess; newNode = newMemberAccess; } newNode = SyntaxFactory.AwaitExpression(newNode) .WithAdditionalAnnotations(Formatter.Annotation) .WithLeadingTrivia(memberAccess.GetLeadingTrivia()) .WithTrailingTrivia(memberAccess.GetTrailingTrivia()); if (oldNode.Parent.Kind() == SyntaxKind.SimpleMemberAccessExpression) { newNode = SyntaxFactory.ParenthesizedExpression(newNode); } var root = await document.GetSyntaxRootAsync().ConfigureAwait(false); var newRoot = root.ReplaceNode(oldNode, newNode); return document.WithSyntaxRoot(newRoot); }
private SyntaxNode GetMemberAccessWithoutThis(MemberAccessExpressionSyntax thisItemAsMemberAccessException) { var right = thisItemAsMemberAccessException.Name; var symbols = semanticModel.LookupSymbols(thisItemAsMemberAccessException.SpanStart, name: right.Identifier.ValueText); var thisItemAsMemberAccessExceptionSymbol = semanticModel.GetSymbolInfo(thisItemAsMemberAccessException).Symbol; if (symbols.Any(x => x == thisItemAsMemberAccessExceptionSymbol)) { return(right.WithLeadingTrivia(thisItemAsMemberAccessException.GetLeadingTrivia())); } return(null); }
private static SyntaxTriviaList GetLeadingTriviaForSimplifiedMemberAccess(MemberAccessExpressionSyntax memberAccess) { // We want to include any user-typed trivia that may be present between the 'Expression', 'OperatorToken' and 'Identifier' of the MemberAccessExpression. // However, we don't want to include any elastic trivia that may have been introduced by the expander in these locations. This is to avoid triggering // aggressive formatting. Otherwise, formatter will see this elastic trivia added by the expander and use that as a cue to introduce unnecessary blank lines // etc. around the user's original code. return(SyntaxFactory.TriviaList(WithoutElasticTrivia( memberAccess.GetLeadingTrivia() .AddRange(memberAccess.Expression.GetTrailingTrivia()) .AddRange(memberAccess.OperatorToken.LeadingTrivia) .AddRange(memberAccess.OperatorToken.TrailingTrivia) .AddRange(memberAccess.Name.GetLeadingTrivia())))); }
public override SyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyntax node) { node = (MemberAccessExpressionSyntax)base.VisitMemberAccessExpression(node); var type = _context.GetNodeContainingClassType(node); if (type == _type && node.Name.ToString() == _memberName) { node = node .WithName(SyntaxFactory.IdentifierName(_newName)) .WithLeadingTrivia(node.GetLeadingTrivia()) .WithTrailingTrivia(node.GetTrailingTrivia()); node = node.CopyAnnotationsTo(node); } return(node); }
public override SyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyntax node) { var symbol = semanticModel.GetSymbolInfo(node.Expression).Symbol; var parent = node.Parent; while (parent != null && !(parent is TypeDeclarationSyntax)) { parent = parent.Parent; } ITypeSymbol thisType = null; if (parent is TypeDeclarationSyntax) { thisType = this.semanticModel.GetDeclaredSymbol(parent) as ITypeSymbol; } node = (MemberAccessExpressionSyntax)base.VisitMemberAccessExpression(node); if (node.Expression is IdentifierNameSyntax && symbol != null && symbol.IsStatic && symbol.ContainingType != null && thisType != null && !thisType.InheritsFromOrEquals(symbol.ContainingType) && (symbol is IMethodSymbol || symbol is IPropertySymbol || symbol is IFieldSymbol || symbol is IEventSymbol)) { return(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(SyntaxFactory.Identifier(node.GetLeadingTrivia(), symbol.FullyQualifiedName(), node.GetTrailingTrivia())), node.OperatorToken, node.Name)); } return(node); }
private static bool TryReduceMemberAccessExpression( MemberAccessExpressionSyntax memberAccess, SemanticModel semanticModel, out TypeSyntax replacementNode, out TextSpan issueSpan, OptionSet optionSet, CancellationToken cancellationToken) { replacementNode = null; issueSpan = default; if (memberAccess.Name == null || memberAccess.Expression == null) return false; // if this node is annotated as being a SpecialType, let's use this information. if (memberAccess.HasAnnotations(SpecialTypeAnnotation.Kind)) { replacementNode = SyntaxFactory.PredefinedType( SyntaxFactory.Token( memberAccess.GetLeadingTrivia(), GetPredefinedKeywordKind(SpecialTypeAnnotation.GetSpecialType(memberAccess.GetAnnotations(SpecialTypeAnnotation.Kind).First())), memberAccess.GetTrailingTrivia())); issueSpan = memberAccess.Span; return true; } // See https://github.com/dotnet/roslyn/issues/40974 // // To be very safe, we only support simplifying code that bound to a symbol without any // sort of problems. We could potentially relax this in the future. However, we would // need to be very careful about the implications of us offering to fixup 'broken' code // in a manner that might end up making things worse or confusing the user. var symbol = SimplificationHelpers.GetOriginalSymbolInfo(semanticModel, memberAccess); if (symbol == null) return false; if (memberAccess.Expression.IsKind(SyntaxKind.ThisExpression) && !SimplificationHelpers.ShouldSimplifyThisOrMeMemberAccessExpression(semanticModel, optionSet, symbol)) { return false; } // if this node is on the left side, we could simplify to aliases if (!memberAccess.IsRightSideOfDot()) { // Check if we need to replace this syntax with an alias identifier if (TryReplaceExpressionWithAlias( memberAccess, semanticModel, symbol, cancellationToken, out var aliasReplacement)) { // get the token text as it appears in source code to preserve e.g. unicode character escaping var text = aliasReplacement.Name; var syntaxRef = aliasReplacement.DeclaringSyntaxReferences.FirstOrDefault(); if (syntaxRef != null) { var declIdentifier = ((UsingDirectiveSyntax)syntaxRef.GetSyntax(cancellationToken)).Alias.Name.Identifier; text = declIdentifier.IsVerbatimIdentifier() ? declIdentifier.ToString().Substring(1) : declIdentifier.ToString(); } replacementNode = SyntaxFactory.IdentifierName( memberAccess.Name.Identifier.CopyAnnotationsTo(SyntaxFactory.Identifier( memberAccess.GetLeadingTrivia(), SyntaxKind.IdentifierToken, text, aliasReplacement.Name, memberAccess.GetTrailingTrivia()))); replacementNode = memberAccess.CopyAnnotationsTo(replacementNode); replacementNode = memberAccess.Name.CopyAnnotationsTo(replacementNode); issueSpan = memberAccess.Span; // In case the alias name is the same as the last name of the alias target, we only include // the left part of the name in the unnecessary span to Not confuse uses. if (memberAccess.Name.Identifier.ValueText == ((IdentifierNameSyntax)replacementNode).Identifier.ValueText) { issueSpan = memberAccess.Expression.Span; } return true; } // Check if the Expression can be replaced by Predefined Type keyword if (PreferPredefinedTypeKeywordInMemberAccess(memberAccess, optionSet, semanticModel)) { if (symbol != null && symbol.IsKind(SymbolKind.NamedType)) { var keywordKind = GetPredefinedKeywordKind(((INamedTypeSymbol)symbol).SpecialType); if (keywordKind != SyntaxKind.None) { replacementNode = CreatePredefinedTypeSyntax(memberAccess, keywordKind); replacementNode = replacementNode .WithAdditionalAnnotations<TypeSyntax>(new SyntaxAnnotation( nameof(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess))); issueSpan = memberAccess.Span; // we want to show the whole expression as unnecessary return true; } } } } // Try to eliminate cases without actually calling CanReplaceWithReducedName. For expressions of the form // 'this.Name' or 'base.Name', no additional check here is required. if (!memberAccess.Expression.IsKind(SyntaxKind.ThisExpression, SyntaxKind.BaseExpression)) { GetReplacementCandidates( semanticModel, memberAccess, symbol, out var speculativeSymbols, out var speculativeNamespacesAndTypes); if (!IsReplacementCandidate(symbol, speculativeSymbols, speculativeNamespacesAndTypes)) { return false; } } replacementNode = memberAccess.GetNameWithTriviaMoved(); issueSpan = memberAccess.Expression.Span; return CanReplaceWithReducedName( memberAccess, replacementNode, semanticModel, symbol, cancellationToken); }
private SyntaxNode GetRoleMethodInvocation(MemberAccessExpressionSyntax node) { var expression = Visit(node.Expression); if (node.Expression != expression) { node = node.ReplaceNode(node.Expression, expression); } if (IsRoleMethodInvocation(node)) { var methodName = ((SimpleNameSyntax)node.Name).Identifier.ValueText; return Syntax.IdentifierName("self__" + GetRoleName(node.Expression) + "__" + methodName).WithLeadingTrivia(node.GetLeadingTrivia()); } return node; }
public override SyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyntax node) { var symbol = semanticModel.GetSymbolInfo(node.Expression).Symbol; node = (MemberAccessExpressionSyntax)base.VisitMemberAccessExpression(node); if (node.Expression is IdentifierNameSyntax && symbol != null && symbol.IsStatic && symbol.ContainingType != null && (symbol is IMethodSymbol || symbol is IPropertySymbol || symbol is IFieldSymbol || symbol is IEventSymbol)) { return(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(SyntaxFactory.Identifier(node.GetLeadingTrivia(), symbol.FullyQualifiedName(), node.GetTrailingTrivia())), node.OperatorToken, node.Name)); } return(node); }
private async Task <Document> InsertAsyncCall(Document document, MemberAccessExpressionSyntax memberAccess, CancellationToken cancellationToken) { var name = memberAccess.Name.Identifier.ValueText; ExpressionSyntax oldNode, newNode, newMemberAccess; switch (name) { case "WaitAny": newMemberAccess = memberAccess.WithName((SimpleNameSyntax)SyntaxFactory.ParseName("WhenAny")); break; case "WaitAll": newMemberAccess = memberAccess.WithName((SimpleNameSyntax)SyntaxFactory.ParseName("WhenAny")); break; case "Wait": newMemberAccess = memberAccess.Expression; break; case "Result": newMemberAccess = memberAccess.Expression; break; case "Sleep": newMemberAccess = SyntaxFactory.ParseExpression("Task.Delay"); break; default: newMemberAccess = memberAccess.WithName((SimpleNameSyntax)SyntaxFactory.ParseName(memberAccess.Name.Identifier.ValueText + "Async")); break; } var invoc = memberAccess.Parent as InvocationExpressionSyntax; // WaitAny, WaitAll, Wait, Sleep, XyzAsync etc. if (invoc != null) { oldNode = invoc; newNode = name == "Wait" ? newMemberAccess : invoc.WithExpression(newMemberAccess); } // t.Result else { oldNode = memberAccess; newNode = newMemberAccess; } newNode = SyntaxFactory.AwaitExpression(newNode) .WithAdditionalAnnotations(Formatter.Annotation) .WithLeadingTrivia(memberAccess.GetLeadingTrivia()) .WithTrailingTrivia(memberAccess.GetTrailingTrivia()); if (oldNode.Parent.Kind() == SyntaxKind.SimpleMemberAccessExpression) { newNode = SyntaxFactory.ParenthesizedExpression(newNode); } var root = await document.GetSyntaxRootAsync().ConfigureAwait(false); var newRoot = root.ReplaceNode(oldNode, newNode); return(document.WithSyntaxRoot(newRoot)); }
private static async Task<Document> FixMember(Document document, MemberAccessExpressionSyntax memberAccessExpression, string apiId, string varName, CancellationToken cancellationToken) { var apiConversion = WinUIAppWindowAnalyzer.MemberApiConversions[apiId]!; if (apiConversion.ToApi is not IMemberDescription) { throw new InvalidOperationException($"Expecting all types in MemberApiConversions dictionary to be of type ITypeMemberDescription but found {apiConversion.ToApi.GetType()}"); } var fromMember = (IMemberDescription)apiConversion.FromApi; var toMember = (IMemberDescription)apiConversion.ToApi; var (newTypeNamespace, newTypeName, newMemberName) = (toMember.TypeDescription.Namespace, toMember.TypeDescription.TypeName, toMember.MemberName); if (apiConversion.NeedsManualUpgradation) { var comment = SyntaxFactory.Comment(@$" /* TODO {WinUIAppWindowAnalyzer.DiagnosticIdAppWindowMember} Use {newTypeNamespace}.{newTypeName}.{newMemberName} instead of {fromMember.MemberName}. Read: {apiConversion.DocumentationUrl} */ "); var existingRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); return document.WithSyntaxRoot(existingRoot!.ReplaceNode(memberAccessExpression, memberAccessExpression.WithLeadingTrivia(comment))); } var documentEditor = await DocumentEditor.CreateAsync(document, cancellationToken).ConfigureAwait(false); var instance = toMember.IsStatic ? $"{newTypeNamespace}.{newTypeName}" : varName; if (toMember.ApiType == ApiType.PropertyApi) { var expr = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ParseExpression(instance), (SimpleNameSyntax)SyntaxFactory.ParseName(newMemberName)); documentEditor.ReplaceNode(memberAccessExpression, expr.WithLeadingTrivia(memberAccessExpression.GetLeadingTrivia())); return document.WithSyntaxRoot(documentEditor.GetChangedRoot()); } var invocationExpression = memberAccessExpression.AncestorsAndSelf().OfType<InvocationExpressionSyntax>().First(); var newExpression = SyntaxFactory.InvocationExpression(SyntaxFactory.ParseExpression($"{instance}.{newMemberName}")); var newExpressionArgs = newExpression.DescendantNodes().OfType<ArgumentListSyntax>().First(); var argsToAdd = invocationExpression.DescendantNodes().OfType<ArgumentListSyntax>().First().Arguments.ToArray(); var newArgs = newExpressionArgs.AddArguments(argsToAdd); var newExpressionWithArgs = newExpression.ReplaceNode(newExpressionArgs, newArgs); if (fromMember.ApiType == ApiType.MethodApi && toMember.ApiType == ApiType.MethodApi && ((MethodDescription)fromMember).IsAsync && !((MethodDescription)toMember).IsAsync) { var awaitExpression = invocationExpression.Ancestors().OfType<AwaitExpressionSyntax>().FirstOrDefault(); if (awaitExpression is not null) { documentEditor.ReplaceNode(awaitExpression, newExpressionWithArgs.WithLeadingTrivia(invocationExpression.GetLeadingTrivia())); return document.WithSyntaxRoot(documentEditor.GetChangedRoot()); } } documentEditor.ReplaceNode(invocationExpression, newExpressionWithArgs.WithLeadingTrivia(invocationExpression.GetLeadingTrivia())); return document.WithSyntaxRoot(documentEditor.GetChangedRoot()); }
private SyntaxNode GetRoleMethodInvocation(MemberAccessExpressionSyntax node) { var expression = Visit(node.Expression); if (node.Expression != expression) { node = node.ReplaceNode(node.Expression, expression); } if (IsRoleMethodInvocation(node)) { var methodName = ((SimpleNameSyntax)node.Name).Identifier.ValueText; return(Syntax.IdentifierName("self__" + GetRoleName(node.Expression) + "__" + methodName).WithLeadingTrivia(node.GetLeadingTrivia())); } return(node); }
public override SyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyntax node) { var esym = m_Model.GetSymbolInfo(node).Symbol as IEventSymbol; var psym = m_Model.GetSymbolInfo(node).Symbol as IPropertySymbol; var fsym = m_Model.GetSymbolInfo(node).Symbol as IFieldSymbol; var msym = m_Model.GetSymbolInfo(node).Symbol as IMethodSymbol; var oper = m_Model.GetOperation(node); SyntaxNode newNode = null; var name = node.Expression as IdentifierNameSyntax; if (null != name) { var text = name.Identifier.Text; foreach (var ns in SymbolTable.Instance.Namespaces) { if (ns == text || ns.Contains("." + text + ".") || ns.EndsWith("." + text)) { newNode = SyntaxFactory.IdentifierName(node.Name.ToString()).WithLeadingTrivia(node.GetLeadingTrivia()).WithTrailingTrivia(node.GetTrailingTrivia()); } } } if (null == newNode) { newNode = base.VisitMemberAccessExpression(node); } bool isExtern = false; INamedTypeSymbol classType = null; if (null != esym && SymbolTable.Instance.IsExternSymbol(esym)) { isExtern = true; classType = esym.ContainingType; newNode = ReportAndAttachError(newNode, string.Format("[Cs2LuaRewriter] Unsupported extern event !")); } if (null != psym && SymbolTable.Instance.IsExternSymbol(psym)) { isExtern = true; classType = psym.ContainingType; if (SymbolTable.Instance.IsIllegalProperty(psym)) { newNode = ReportAndAttachError(newNode, string.Format("[Cs2LuaRewriter] Unsupported extern property !")); } } if (null != fsym && SymbolTable.Instance.IsExternSymbol(fsym)) { isExtern = true; classType = fsym.ContainingType; if (SymbolTable.Instance.IsIllegalField(fsym)) { newNode = ReportAndAttachError(newNode, string.Format("[Cs2LuaRewriter] Unsupported extern field !")); } } if (null != msym && !(node.Parent is InvocationExpressionSyntax) && SymbolTable.Instance.IsExternSymbol(msym.ContainingType)) { if (SymbolTable.Instance.IsIllegalMethod(msym)) { newNode = ReportAndAttachError(newNode, "[Cs2LuaRewriter] Unsupported extern method !"); } } if (isExtern && null != oper) { bool legal = true; SymbolTable.TryRemoveNullable(ref classType); if (null != classType && (classType.TypeKind == TypeKind.Delegate || classType.IsGenericType && SymbolTable.Instance.IsLegalGenericType(classType, true))) { //如果是标记为合法的泛型类或委托类型的成员,则不用再进行类型检查 } else { var type = oper.Type as INamedTypeSymbol; SymbolTable.TryRemoveNullable(ref type); if (null != type && SymbolTable.Instance.IsExternSymbol(type) && type.TypeKind != TypeKind.Delegate) { if (type.IsGenericType) { if (!SymbolTable.Instance.IsLegalParameterGenericType(type)) { legal = false; } } else { if (SymbolTable.Instance.IsIllegalType(type)) { legal = false; } } } } if (!legal) { newNode = ReportAndAttachError(newNode, string.Format("[Cs2LuaRewriter] Unsupported extern type from member access !")); } } return(newNode); }