public override LookupResult Lookup(SimpleNameSyntax name, Package fromPackage) { return name.Match().Returning<LookupResult>() .With<IdentifierNameSyntax>(identifierName => { var identifier = identifierName.Identifier.ValueText; var members = symbols.SelectMany(r => r.GetMembers(identifier)).ToList(); // TODO this looks like a duplicate of the Resolve method on ContainerBinder if(members.Count == 0) return Empty; var visible = members.Where(m => m.IsVisibleFrom(fromPackage)).ToList(); if(visible.Count == 1) return Good(visible.Single()); var visibleInPackage = visible.Where(r => r.IsIn(fromPackage)).ToList(); if(visibleInPackage.Count == 1) return Good(visibleInPackage.Single()); // TODO issue warning that we have chosen the one in the current package if(visibleInPackage.Count > 1 || visible.Count > 1) return Ambiguous(visible); // Nothing visible in package if(members.Count > 0) return NotAccessible(members); return NotDefined(); }) .Exhaustive(); }
// returns true if the idenfitier meets requirements // for adding the 'this' keyword prefix private bool IsCandidateForThis(SimpleNameSyntax node, ISymbol symbol) { if (symbol == null || symbol.ContainingType == null || symbol.IsStatic) return false; if (node.Parent.Kind == SyntaxKind.MemberAccessExpression) { var memberAcc = node.Parent as MemberAccessExpressionSyntax; if (memberAcc.Expression != node) return false; } switch (symbol.Kind) { case CommonSymbolKind.Field: case CommonSymbolKind.Property: case CommonSymbolKind.Event: return true; case CommonSymbolKind.Method: if (((IMethodSymbol)symbol).MethodKind != CommonMethodKind.Constructor) return true; else break; } return false; }
// get the symbol for from the identifier private ISymbol GetSymbol(SimpleNameSyntax node) { var info = Semantics.GetSymbolInfo(node); if (info.Symbol != null) return info.Symbol; if (info.CandidateSymbols.Count == 1) return info.CandidateSymbols[0]; return null; }
// return true the the physical container matches the specified symbol private bool ContainingTypeMatches(SimpleNameSyntax node, INamedTypeSymbol symbol) { TypeDeclarationSyntax value = null; var parent = node.Parent; while (parent != null) { value = parent as TypeDeclarationSyntax; if (value != null) break; parent = parent.Parent; } if (value == null) return false; return Semantics.GetDeclaredSymbol(value).Equals(symbol); }
// carries out the actual rewrite process, if required private SyntaxNode RewriteSyntax(SimpleNameSyntax node) { var symbol = GetSymbol(node); if (symbol == null) return node; if (IsCandidateForThis(node, symbol) && ContainingTypeMatches(node, symbol.ContainingType)) { // rewrite the syntax to include 'this' keyword return Syntax.MemberAccessExpression( SyntaxKind.MemberAccessExpression, Syntax.ThisExpression( Syntax.Token(SyntaxKind.ThisKeyword)), Syntax.Token(SyntaxKind.DotToken), Syntax.IdentifierName(node.Identifier.ValueText)); } return node; }
public static SyntaxNode MethodInvocation(string name, MethodBase methodInfo, SyntaxNode instance, List <ArgumentSyntax> argumentList, TypeArgumentListSyntax typeArgumentList) { var sepList = SyntaxFactory.SeparatedList(argumentList); if (methodInfo == null) { return(SyntaxFactory.EmptyStatement()); } var propertyInfos = methodInfo.DeclaringType?.GetProperties(); var isSetAccessor = propertyInfos?.FirstOrDefault(prop => prop.GetSetMethod() == methodInfo); var isGetAccessor = propertyInfos?.FirstOrDefault(prop => prop.GetGetMethod() == methodInfo); bool isProperty = isSetAccessor != null || isGetAccessor != null; var methodName = methodInfo.Name; if (isProperty) { methodName = name.Substring(4); } bool isGenericMethod = methodInfo.IsGenericMethod; ExpressionSyntax finalExpressionSyntax = null; ExpressionSyntax memberAccessExpression = instance == null?SyntaxFactory.IdentifierName(methodInfo.DeclaringType?.Name) : instance as ExpressionSyntax; if (!isProperty) { if (methodInfo.IsConstructor) { finalExpressionSyntax = SyntaxFactory.ObjectCreationExpression( TypeSystem.BuildTypeSyntax(methodInfo.DeclaringType)) .WithArgumentList(SyntaxFactory.ArgumentList(sepList)); } else { SimpleNameSyntax genericName = isGenericMethod ? (SimpleNameSyntax)SyntaxFactory.GenericName( SyntaxFactory.Identifier(methodName)) .WithTypeArgumentList(typeArgumentList) : SyntaxFactory.IdentifierName(methodName); InvocationExpressionSyntax invocation = SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, memberAccessExpression, genericName )); finalExpressionSyntax = invocation .WithArgumentList(SyntaxFactory.ArgumentList(sepList)); } } else { if (isGetAccessor != null) { if (isGetAccessor.GetIndexParameters().Length > 0) { finalExpressionSyntax = SyntaxFactory.ElementAccessExpression( memberAccessExpression, SyntaxFactory.BracketedArgumentList(sepList)); } else { finalExpressionSyntax = SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, memberAccessExpression, SyntaxFactory.IdentifierName(methodName)); } } else if (isSetAccessor != null) { ExpressionSyntax left; if (isSetAccessor.GetIndexParameters().Length > 0) { left = SyntaxFactory.ElementAccessExpression(memberAccessExpression, SyntaxFactory.BracketedArgumentList( SyntaxFactory.SeparatedList(argumentList.Take(argumentList.Count - 1)) )); } else { left = SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, memberAccessExpression, SyntaxFactory.IdentifierName(methodName)); } finalExpressionSyntax = SyntaxFactory.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, left, argumentList.Last().Expression); } } return(finalExpressionSyntax); }
private static bool IsQualified(SimpleNameSyntax identifierName) { return(identifierName.IsParentKind(SyntaxKind.SimpleMemberAccessExpression)); }
private static bool IsSelectingADifferentMethod(IEnumerable <SyntaxNode> childNodes, SimpleNameSyntax methodName, SyntaxTree tree, IMethodSymbol methodSymbol, StatementSyntax invocationStatement, Compilation compilation) { var parameterExpressions = CallExtensionMethodAsExtensionCodeFixProvider.GetParameterExpressions(childNodes); var firstArgument = parameterExpressions.FirstOrDefault(); var argumentList = CallExtensionMethodAsExtensionCodeFixProvider.CreateArgumentListSyntaxFrom(parameterExpressions.Skip(1)); var newInvocationStatement = SyntaxFactory.ExpressionStatement( CallExtensionMethodAsExtensionCodeFixProvider.CreateInvocationExpression( firstArgument, methodName, argumentList)).WithAdditionalAnnotations(introduceExtensionMethodAnnotation); var extensionMethodNamespaceUsingDirective = SyntaxFactory.UsingDirective(methodSymbol.ContainingNamespace.ToNameSyntax()); var speculativeRootWithExtensionMethod = tree.GetCompilationUnitRoot() .ReplaceNode(invocationStatement, newInvocationStatement) .AddUsings(extensionMethodNamespaceUsingDirective); var speculativeModel = compilation.ReplaceSyntaxTree(tree, speculativeRootWithExtensionMethod.SyntaxTree) .GetSemanticModel(speculativeRootWithExtensionMethod.SyntaxTree); var speculativeInvocationStatement = speculativeRootWithExtensionMethod.SyntaxTree.GetCompilationUnitRoot().GetAnnotatedNodes(introduceExtensionMethodAnnotation).Single() as ExpressionStatementSyntax; var speculativeExtensionMethodSymbol = speculativeModel.GetSymbolInfo(speculativeInvocationStatement.Expression).Symbol as IMethodSymbol; var speculativeNonExtensionFormOfTheMethodSymbol = speculativeExtensionMethodSymbol?.GetConstructedReducedFrom(); return(speculativeNonExtensionFormOfTheMethodSymbol == null || !speculativeNonExtensionFormOfTheMethodSymbol.Equals(methodSymbol)); }
private static async Task ComputeCodeFixAsync(CodeFixContext context, Diagnostic diagnostic, ExpressionSyntax expression, SimpleNameSyntax simpleName) { switch (simpleName.Identifier.ValueText) { case "Count": { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ComputeCodeFix(context, diagnostic, expression, simpleName, semanticModel, "Count", "Length"); break; } case "Length": { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ComputeCodeFix(context, diagnostic, expression, simpleName, semanticModel, "Length", "Count"); break; } } }
public static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context) { var invocation = (InvocationExpressionSyntax)context.Node; ExpressionSyntax expression = invocation.Expression; if (expression?.IsKind(SyntaxKind.SimpleMemberAccessExpression) == true) { var memberAccess = (MemberAccessExpressionSyntax)expression; ArgumentListSyntax argumentList = invocation.ArgumentList; if (argumentList != null) { SeparatedSyntaxList <ArgumentSyntax> arguments = argumentList.Arguments; if (arguments.Any()) { SimpleNameSyntax name = memberAccess.Name; if (name?.Identifier.ValueText == "Join") { SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; if (semanticModel.TryGetMethodInfo(invocation, out MethodInfo info, cancellationToken) && info.IsName("Join") && info.IsContainingType(SpecialType.System_String) && info.IsPublic && info.IsStatic && info.IsReturnType(SpecialType.System_String) && !info.IsGenericMethod && !info.IsExtensionMethod) { ImmutableArray <IParameterSymbol> parameters = info.Parameters; if (parameters.Length == 2 && parameters[0].Type.IsString()) { IParameterSymbol parameter = parameters[1]; if (parameter.IsParamsOf(SpecialType.System_String, SpecialType.System_Object) || parameter.Type.IsConstructedFromIEnumerableOfT()) { ArgumentSyntax firstArgument = arguments.First(); ExpressionSyntax argumentExpression = firstArgument.Expression; if (argumentExpression != null && CSharpUtility.IsEmptyString(argumentExpression, semanticModel, cancellationToken) && !invocation.ContainsDirectives(TextSpan.FromBounds(invocation.SpanStart, firstArgument.Span.End))) { context.ReportDiagnostic( DiagnosticDescriptors.CallStringConcatInsteadOfStringJoin, name); } } } } } } } } }
public abstract LookupResult Lookup(SimpleNameSyntax name, Package fromPackage);
private static bool IsSelectingADifferentMethod(IEnumerable <SyntaxNode> childNodes, SimpleNameSyntax methodName, SyntaxTree tree, IMethodSymbol methodSymbol, ExpressionSyntax invocationExpression, Compilation compilation) { var parameterExpressions = GetParameterExpressions(childNodes); var firstArgument = parameterExpressions.FirstOrDefault(); var argumentList = CreateArgumentListSyntaxFrom(parameterExpressions.Skip(1)); var newInvocationStatement = CreateInvocationExpression(firstArgument, methodName, argumentList) .WithAdditionalAnnotations(introduceExtensionMethodAnnotation); var extensionMethodNamespaceUsingDirective = SyntaxFactory.UsingDirective(methodSymbol.ContainingNamespace.ToNameSyntax()); var speculativeRootWithExtensionMethod = tree.GetCompilationUnitRoot() .ReplaceNode(invocationExpression, newInvocationStatement) .AddUsings(extensionMethodNamespaceUsingDirective); var speculativeTree = speculativeRootWithExtensionMethod.SyntaxTree; var speculativeTreeOptions = (CSharpParseOptions)speculativeTree.Options; var speculativeTreeWithCorrectLanguageVersion = speculativeTree.WithRootAndOptions(speculativeRootWithExtensionMethod, speculativeTreeOptions.WithLanguageVersion(((CSharpParseOptions)tree.Options).LanguageVersion)); var speculativeModel = compilation.ReplaceSyntaxTree(tree, speculativeTreeWithCorrectLanguageVersion) .GetSemanticModel(speculativeTreeWithCorrectLanguageVersion); var speculativeInvocationStatement = speculativeTreeWithCorrectLanguageVersion.GetCompilationUnitRoot().GetAnnotatedNodes(introduceExtensionMethodAnnotation).Single() as InvocationExpressionSyntax; var speculativeExtensionMethodSymbol = speculativeModel.GetSymbolInfo(speculativeInvocationStatement.Expression).Symbol as IMethodSymbol; var speculativeNonExtensionFormOfTheMethodSymbol = speculativeExtensionMethodSymbol?.GetConstructedReducedFrom(); return(speculativeNonExtensionFormOfTheMethodSymbol == null || speculativeNonExtensionFormOfTheMethodSymbol.ToString() != methodSymbol.ToString());//can't compare equality, as speculative symbol might be different }
// return true the the physical container matches the specified symbol private bool ContainingTypeMatches(SimpleNameSyntax node, INamedTypeSymbol symbol) { TypeDeclarationSyntax value = null; var parent = node.Parent; while (parent != null) { value = parent as TypeDeclarationSyntax; if (value != null) break; parent = parent.Parent; } if (value == null) return false; var typeSym = Semantics.GetDeclaredSymbol(value) as INamedTypeSymbol; // the symbol can match any type in the inheritance chain while (typeSym != null) { if (typeSym.Equals(symbol)) return true; typeSym = typeSym.BaseType; } return false; }
private ExpressionNode BindMemberAccess(SyntaxNode node, ExpressionNode left, SimpleNameSyntax right, bool invoked) { Debug.Assert(node != null); Debug.Assert(left != null); Debug.Assert(right != null); Debug.Assert(node != null); // A member-access consists of a primary-expression, a predefined-type, or a // qualified-alias-member, followed by a "." token, followed by an identifier, // optionally followed by a type-argument-list. // A member-access is either of the form E.I or of the form E.I<A1, ..., AK>, // where E is a primary-expression, I is a single identifier and <A1, ..., AK> // is an optional type-argument-list. When no type-argument-list is specified, // consider K to be zero. // UNDONE: A member-access with a primary-expression of type dynamic is dynamically bound. // UNDONE: In this case the compiler classifies the member access as a property access of // UNDONE: type dynamic. The rules below to determine the meaning of the member-access are // UNDONE: then applied at run-time, using the run-time type instead of the compile-time // UNDONE: type of the primary-expression. If this run-time classification leads to a method // UNDONE: group, then the member access must be the primary-expression of an invocation-expression. // The member-access is evaluated and classified as follows: string rightName = right.PlainName; int rightArity = right.Arity; LookupResult lookupResult = new LookupResult(); if (left.Kind == NodeKind.NamespaceExpression) { // If K is zero and E is a namespace and E contains a nested namespace with name I, // then the result is that namespace. var ns = ((NamespaceExpression)left).NamespaceSymbol; lookupResult = MemberLookupInNamespace(ns, rightName, rightArity); // UNDONE: Report errors if more than one, or none. if (lookupResult.IsViable) { Symbol sym = lookupResult.Symbols.First(); if (sym.Kind == SymbolKind.Namespace) return new NamespaceExpression(node, (NamespaceSymbol)sym); else { Debug.Assert(sym.Kind == SymbolKind.NamedType); return new TypeExpression(node, (NamedTypeSymbol)sym); } } else { return null; } #if SLOW if (node.Right.Arity == 0) { var childnamespaces = ns.GetMembers(node.Right.Identifier.ValueText).OfType<NamespaceSymbol>(); var childnamespace = childnamespaces.SingleOrDefault(); if (childnamespace != null) { return new NamespaceExpression(node, childnamespace); } } // Otherwise, if E is a namespace and E contains an accessible type having name I and K type // parameters, then the result is that type constructed with the given type arguments. var childTypes = ns.GetMembers(node.Right.Identifier.Text).OfType<NamedTypeSymbol>().Where(s => s.Arity == node.Right.Arity && IsMemberAccessible(s)); var childType = childTypes.SingleOrDefault(); if (childType != null) { // UNDONE: Construct the child type if it is generic! return new TypeExpression(node, childType); } #endif } // If E is a predefined-type or a primary-expression classified as a type, if E is not a // type parameter, and if a member lookup of I in E with K type parameters produces a // match, then E.I is evaluated and classified as follows: else if (left.Kind == NodeKind.TypeExpression) { var type = ((TypeExpression)left).Type; if (!(type is TypeParameterSymbol)) { lookupResult = MemberLookup(type, rightName, rightArity, invoked); if (lookupResult.IsViable) { return BindStaticMemberOfType(node, left, right, lookupResult); } } } // If E is a property access, indexer access, variable, or value, the type of which is T, // and a member lookup of I in T with K type arguments produces a match, then E.I // is evaluated and classified as follows: // UNDONE: Classify E as prop access, indexer access, variable or value else { var type = ((ValueNode)left).Type; lookupResult = MemberLookup(type, rightName, rightArity, invoked); if (lookupResult.IsViable) { return BindInstanceMemberOfType(node, type, left, right, lookupResult); } } // UNDONE: Otherwise, an attempt is made to process E.I as an extension method invocation. // UNDONE: If this fails, E.I is an invalid member reference, and a binding-time error occurs. return null; }
private ExpressionNode BindInstanceMemberOfType(SyntaxNode node, TypeSymbol type, ExpressionNode left, SimpleNameSyntax right, LookupResult lookupResult) { Debug.Assert(left != null); Debug.Assert(right != null); Debug.Assert(node != null); Debug.Assert(lookupResult.IsViable); Debug.Assert(lookupResult.Symbols.Any()); // UNDONE: First, if E is a property or indexer access, then the value of the property or indexer access is obtained (§7.1.1) and E is reclassified as a value. SymbolOrMethodGroup symbolOrMethods = GetSymbolOrMethodGroup(lookupResult); if (symbolOrMethods.IsMethodGroup) { // If I identifies one or more methods, then the result is a method group with an associated // instance expression of E. If a type argument list was specified, it is used in calling // a generic method. // UNDONE: Construct the type argument list if there is one. return new MethodGroup(right, null, left, symbolOrMethods.MethodGroup); } // UNDONE: If I identifies an instance property, then the result is a property access with an associated instance expression of E. // UNDONE: If T is a class-type and I identifies an instance field of that class-type: // UNDONE: If the value of E is null, then a System.NullReferenceException is thrown. // UNDONE: Otherwise, if the field is readonly and the reference occurs outside an instance constructor of the class in which the field is declared, then the result is a value, namely the value of the field I in the object referenced by E. // UNDONE: Otherwise, the result is a variable, namely the field I in the object referenced by E. // UNDONE: If T is a struct-type and I identifies an instance field of that struct-type: // UNDONE: If E is a value, or if the field is readonly and the reference occurs outside an instance constructor of the struct in which the field is declared, then the result is a value, namely the value of the field I in the struct instance given by E. // UNDONE: Otherwise, the result is a variable, namely the field I in the struct instance given by E. // UNDONE: If I identifies an instance event: // UNDONE: If the reference occurs within the class or struct in which the event is declared, and the event was declared without event-accessor-declarations (§10.8), then E.I is processed exactly as if I was an instance field. // UNDONE: Otherwise, the result is an event access with an associated instance expression of E. return null; }
private static string GetMessage(SimpleNameSyntax identifier) => IsArgumentOfConstructorInitializer(identifier) ? string.Format(Constructor, identifier.Identifier.ValueText) : string.Format(Method, identifier.Identifier.ValueText);
private static IMethodSymbol GetCallerMethodSymbol(SemanticModel semanticModel, SimpleNameSyntax name, int argumentsCount) { var symbolInfo = semanticModel.GetSymbolInfo(name); return(symbolInfo.Symbol as IMethodSymbol ?? symbolInfo .CandidateSymbols .OfType <IMethodSymbol>() .FirstOrDefault(s => s.Parameters.Length == argumentsCount + 1)); }
private MethodDeclarationSyntax CreateKeyValueMethod(MetaField field, IdentifierNameSyntax methodName, SimpleNameSyntax collectionMutationMethodName) { var paramsArrayMethod = CreateMethodStarter(methodName.Identifier, field) .WithParameterList(SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList( new ParameterSyntax[] { SyntaxFactory.Parameter(KeyParameterName.Identifier).WithType(GetFullyQualifiedSymbolName(field.ElementKeyType)), SyntaxFactory.Parameter(ValueParameterName.Identifier).WithType(GetFullyQualifiedSymbolName(field.ElementValueType)), }))); paramsArrayMethod = this.AddMethodBody( paramsArrayMethod, field, receiver => SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, receiver, collectionMutationMethodName), SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(new ArgumentSyntax[] { SyntaxFactory.Argument(KeyParameterName), SyntaxFactory.Argument(ValueParameterName), })))); return(paramsArrayMethod); }
private static void AnalyzeBinaryExpression(SyntaxNodeAnalysisContext context) { var binaryExpression = (BinaryExpressionSyntax)context.Node; BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo(binaryExpression); if (!binaryExpressionInfo.Success) { return; } if (binaryExpressionInfo.Right.Kind() != SyntaxKind.TrueLiteralExpression) { return; } ExpressionSyntax left = binaryExpressionInfo.Left; if (left.Kind() != SyntaxKind.ConditionalAccessExpression) { return; } var conditionalAccess = (ConditionalAccessExpressionSyntax)left; ExpressionSyntax whenNotNull = conditionalAccess.WhenNotNull; if (whenNotNull.Kind() != SyntaxKind.InvocationExpression) { return; } var invocationExpression = (InvocationExpressionSyntax)whenNotNull; if (invocationExpression.ArgumentList.Arguments.Count != 1) { return; } ExpressionSyntax expression = invocationExpression.Expression; if (expression.Kind() != SyntaxKind.MemberBindingExpression) { return; } var memberBindingExpression = (MemberBindingExpressionSyntax)expression; SimpleNameSyntax name = memberBindingExpression.Name; if (name.Kind() != SyntaxKind.IdentifierName) { return; } var identifierName = (IdentifierNameSyntax)name; if (!string.Equals(identifierName.Identifier.ValueText, "IsKind", StringComparison.Ordinal)) { return; } ISymbol symbol = context.SemanticModel.GetSymbol(invocationExpression, context.CancellationToken); if (symbol?.Kind != SymbolKind.Method) { return; } var methodSymbol = (IMethodSymbol)symbol; if (methodSymbol.MethodKind != MethodKind.ReducedExtension) { return; } if (methodSymbol.ReturnType.SpecialType != SpecialType.System_Boolean) { return; } if (methodSymbol.ContainingType?.HasMetadataName(RoslynMetadataNames.Microsoft_CodeAnalysis_CSharpExtensions) != true) { return; } ImmutableArray <IParameterSymbol> parameters = methodSymbol .ReducedFrom .Parameters; if (parameters.Length != 2) { return; } if (!parameters[0].Type.HasMetadataName(RoslynMetadataNames.Microsoft_CodeAnalysis_SyntaxNode)) { return; } if (!parameters[1].Type.HasMetadataName(CSharpMetadataNames.Microsoft_CodeAnalysis_CSharp_SyntaxKind)) { return; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UnnecessaryConditionalAccess, conditionalAccess.OperatorToken); DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UnnecessaryConditionalAccessFadeOut, binaryExpression.Right); }
async Task <Solution> PerformAction(Document document, SemanticModel model, SyntaxNode root, TypeDeclarationSyntax enclosingTypeDeclaration, INamedTypeSymbol declaringTypeSymbol, MethodDeclarationSyntax methodDeclaration, IMethodSymbol methodSymbol, CancellationToken cancellationToken) { // Collect all invocations of changed method var methodReferencesVisitor = new MethodReferencesVisitor(document.Project.Solution, methodSymbol, methodDeclaration, cancellationToken); await methodReferencesVisitor.Collect(); // Collect all references to type members and "this" expressions inside of changed method var memberReferencesVisitor = new MemberReferencesVisitor(model, declaringTypeSymbol.GetMembers().Where(m => m != methodSymbol), cancellationToken); memberReferencesVisitor.Collect(methodDeclaration.Body); Solution solution = document.Project.Solution; List <SyntaxNode> trackedNodesInMainDoc = new List <SyntaxNode>(); trackedNodesInMainDoc.Add(methodDeclaration); var methodReferencesInMainDocument = methodReferencesVisitor.NodesToChange.FirstOrDefault(n => n.Document.Id == document.Id); if (methodReferencesInMainDocument != null) { trackedNodesInMainDoc.AddRange(methodReferencesInMainDocument.References.Select(r => r.InvocationExpression)); } trackedNodesInMainDoc.AddRange(memberReferencesVisitor.NodesToChange); var newMainRoot = root.TrackNodes(trackedNodesInMainDoc); foreach (var invocationsInDocument in methodReferencesVisitor.NodesToChange) { SyntaxNode thisDocRoot = null; var thisDocumentId = invocationsInDocument.Document.Id; if (document.Id == thisDocumentId) { // We are in same document as changed method declaration, reuse new root from outside thisDocRoot = newMainRoot; } else { thisDocRoot = await invocationsInDocument.Document.GetSyntaxRootAsync(); if (thisDocRoot == null) { continue; } thisDocRoot = thisDocRoot.TrackNodes(invocationsInDocument.References.Select(r => r.InvocationExpression)); } foreach (var referencingInvocation in invocationsInDocument.References) { // Change this method invocation to invocation of a static method with instance parameter var thisInvocation = thisDocRoot.GetCurrentNode(referencingInvocation.InvocationExpression); ExpressionSyntax invocationExpressionPart = null; SimpleNameSyntax methodName = null; var memberAccessExpr = thisInvocation.Expression as MemberAccessExpressionSyntax; if (memberAccessExpr != null) { invocationExpressionPart = memberAccessExpr.Expression; methodName = memberAccessExpr.Name; } if (invocationExpressionPart == null) { var identifier = thisInvocation.Expression as IdentifierNameSyntax; if (identifier != null) { // If changed method references itself, use "instance" as additional parameter! In other methods of affected class, use "this"! if (referencingInvocation.IsInChangedMethod) { invocationExpressionPart = SyntaxFactory.IdentifierName("instance").WithLeadingTrivia(identifier.GetLeadingTrivia()); } else { invocationExpressionPart = SyntaxFactory.ThisExpression().WithLeadingTrivia(identifier.GetLeadingTrivia()); } methodName = identifier; } } if (invocationExpressionPart == null) { continue; } List <ArgumentSyntax> invocationArguments = new List <ArgumentSyntax>(); invocationArguments.Add(SyntaxFactory.Argument(invocationExpressionPart.WithoutLeadingTrivia())); invocationArguments.AddRange(referencingInvocation.InvocationExpression.ArgumentList.Arguments); thisDocRoot = thisDocRoot.ReplaceNode( thisInvocation, SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName(enclosingTypeDeclaration.Identifier.WithoutTrivia()).WithLeadingTrivia(invocationExpressionPart.GetLeadingTrivia()), methodName.WithoutLeadingTrivia() ), SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(invocationArguments)).WithAdditionalAnnotations(Formatter.Annotation) )); } if (document.Id == thisDocumentId) { // Write new root back to outside newMainRoot = thisDocRoot; } else { // Another document, replace it with modified version in solution solution = solution.WithDocumentSyntaxRoot(thisDocumentId, thisDocRoot); } } foreach (var changedNode in memberReferencesVisitor.NodesToChange) { var trackedNode = newMainRoot.GetCurrentNode(changedNode); var thisExpression = trackedNode as ThisExpressionSyntax; if (thisExpression != null) { // Replace "this" with instance parameter name newMainRoot = newMainRoot.ReplaceNode( thisExpression, SyntaxFactory.IdentifierName("instance").WithLeadingTrivia(thisExpression.GetLeadingTrivia()) ); } var memberIdentifier = trackedNode as IdentifierNameSyntax; if (memberIdentifier != null) { newMainRoot = newMainRoot.ReplaceNode( memberIdentifier, SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.IdentifierName("instance").WithLeadingTrivia(memberIdentifier.GetLeadingTrivia()), memberIdentifier.WithoutLeadingTrivia()) ); } } List <ParameterSyntax> parameters = new List <ParameterSyntax>(); parameters.Add(SyntaxFactory.Parameter( SyntaxFactory.List <AttributeListSyntax>(), SyntaxFactory.TokenList(), SyntaxFactory.ParseTypeName(enclosingTypeDeclaration.Identifier.ValueText), SyntaxFactory.Identifier("instance"), null) .WithAdditionalAnnotations(Formatter.Annotation)); parameters.AddRange(methodDeclaration.ParameterList.Parameters); var staticModifierLeadingTrivia = methodDeclaration.Modifiers.Any() ? SyntaxFactory.TriviaList() : methodDeclaration.GetLeadingTrivia(); var methodDeclarationLeadingTrivia = methodDeclaration.Modifiers.Any() ? methodDeclaration.GetLeadingTrivia() : SyntaxFactory.TriviaList(); var trackedMethodDeclaration = newMainRoot.GetCurrentNode(methodDeclaration); newMainRoot = newMainRoot.ReplaceNode((SyntaxNode)trackedMethodDeclaration, trackedMethodDeclaration .WithLeadingTrivia(methodDeclarationLeadingTrivia) .WithModifiers(trackedMethodDeclaration.Modifiers.Add(SyntaxFactory.Token(SyntaxKind.StaticKeyword).WithLeadingTrivia(staticModifierLeadingTrivia).WithTrailingTrivia(SyntaxFactory.TriviaList(SyntaxFactory.Whitespace(" "))))) .WithParameterList(SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters)).WithTrailingTrivia(trackedMethodDeclaration.ParameterList.GetTrailingTrivia()))); return(solution.WithDocumentSyntaxRoot(document.Id, newMainRoot)); }
private ExpressionNode BindStaticMemberOfType(SyntaxNode node, ExpressionNode left, SimpleNameSyntax right, LookupResult lookupResult) { Debug.Assert(node != null); Debug.Assert(left != null); Debug.Assert(right != null); Debug.Assert(lookupResult.IsViable); Debug.Assert(lookupResult.Symbols.Any()); SymbolOrMethodGroup symbolOrMethods = GetSymbolOrMethodGroup(lookupResult); if (symbolOrMethods.IsMethodGroup) { // If I identifies one or more methods, then the result is a method group with no // associated instance expression. If a type argument list was specified, it is used // in calling a generic method. // UNDONE: Construct the type argument list if there is one. return new MethodGroup(right, null, left, symbolOrMethods.MethodGroup); } else { Symbol symbol = symbolOrMethods.NonMethod; switch (symbol.Kind) { case SymbolKind.NamedType: case SymbolKind.ErrorType: // If I identifies a type, then the result is that type constructed with the given type arguments. // UNDONE: Construct the child type if it is generic! return new TypeExpression(node, (TypeSymbol)symbol); case SymbolKind.Property: // If I identifies a static property, then the result is a property access with no // associated instance expression. // UNDONE: give error if not static. return null; case SymbolKind.Field: // If I identifies a static field: // UNDONE: If the field is readonly and the reference occurs outside the static constructor of // UNDONE: the class or struct in which the field is declared, then the result is a value, namely // UNDONE: the value of the static field I in E. // UNDONE: Otherwise, the result is a variable, namely the static field I in E. // UNDONE: Need a way to mark an expression node as "I am a variable, not a value". // UNDONE: Give error for non-static. return null; default: Debug.Fail("Unexpected symbol kind"); return null; } } }
private static bool IsValidGetter(ArgumentSyntax argument, SemanticModel semanticModel, INamedTypeSymbol containingType, out IPropertySymbol propertySymbol, out SimpleNameSyntax nameSyntax) { propertySymbol = null; nameSyntax = null; var expression = argument.GetExpression(); if (!(expression is SingleLineLambdaExpressionSyntax lambdaExpression)) { return(false); } if (!(lambdaExpression.Body is MemberAccessExpressionSyntax memberAccessExpression)) { return(false); } if (!memberAccessExpression.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { return(false); } if (!(semanticModel.GetSymbolInfo(memberAccessExpression).Symbol is IPropertySymbol result)) { return(false); } if (result.ContainingType != containingType) { return(false); } if (result.SetMethod == null) { return(false); } propertySymbol = result; nameSyntax = memberAccessExpression.Name; return(true); }
/// <summary> /// Tries to get the list of candidate methods that can /// override the specified virtual call. /// </summary> /// <param name="overriders">List of overrider methods</param> /// <param name="virtualCall">Virtual call</param> /// <param name="node">IDataFlowNode</param> /// <returns>Boolean</returns> private static bool TryGetCandidateMethodOverriders(out HashSet <MethodDeclarationSyntax> overriders, InvocationExpressionSyntax virtualCall, IDataFlowNode node) { overriders = new HashSet <MethodDeclarationSyntax>(); ISymbol calleeSymbol = null; SimpleNameSyntax callee = null; bool isThis = false; if (virtualCall.Expression is MemberAccessExpressionSyntax) { var expr = virtualCall.Expression as MemberAccessExpressionSyntax; var identifier = expr.Expression.DescendantNodesAndSelf(). OfType <IdentifierNameSyntax>().Last(); calleeSymbol = node.Summary.SemanticModel.GetSymbolInfo(identifier).Symbol; if (expr.Expression is ThisExpressionSyntax) { callee = expr.Name; isThis = true; } } else { callee = virtualCall.Expression as IdentifierNameSyntax; isThis = true; } if (isThis) { var typeDeclaration = node.Summary.Method.FirstAncestorOrSelf <TypeDeclarationSyntax>(); if (typeDeclaration != null) { foreach (var method in typeDeclaration.Members.OfType <MethodDeclarationSyntax>()) { if (method.Identifier.ToString().Equals(callee.Identifier.ToString())) { overriders.Add(method); return(true); } } } return(false); } var calleeDefinitions = node.DataFlowInfo.ResolveOutputAliases(calleeSymbol); var calleeTypes = calleeDefinitions.SelectMany(def => def.CandidateTypes); if (!calleeTypes.Any()) { return(false); } foreach (var calleeType in calleeTypes) { MethodDeclarationSyntax method = null; if (MethodSummaryResolver.TryGetMethodDeclarationFromType( out method, calleeType, virtualCall, node)) { overriders.Add(method); } } return(true); }
public static MemberAccessExpressionSyntax MemberAccessExpression(ExpressionSyntax expression, SimpleNameSyntax name) => SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, expression, name);
private static string GetSimpleTypeName(SimpleNameSyntax name) => name.Identifier.ValueText;
public static InvocationExpressionSyntax InvocationExpression(string identifier, SimpleNameSyntax name, params ArgumentSyntax[] arguments) => InvocationExpression(IdentifierName(identifier), name, arguments);
public static QualifiedNameSyntax QualifiedName(NameSyntax left, SyntaxToken dotToken, SimpleNameSyntax right) { return new QualifiedNameSyntax (left, dotToken, right); }
public static InvocationExpressionSyntax InvocationExpression(ExpressionSyntax expression, SimpleNameSyntax name, params ArgumentSyntax[] arguments) => InvocationExpression(MemberAccessExpression(expression, name), (IEnumerable <ArgumentSyntax>)arguments);
public MemberInvocationExpressionWithSingleParameter(ExpressionSyntax expression, SimpleNameSyntax name, ArgumentSyntax argument) { Expression = expression; Name = name; Argument = argument; }
public static bool ParseInvocation(InvocationExpressionSyntax invocation, out ContractInvocationInfo invocationInfo) { if (invocation.ArgumentList.Arguments.Count >= 1 && invocation.ArgumentList.Arguments.Count <= 3 && invocation.Expression is MemberAccessExpressionSyntax memberAccess && memberAccess.Name is SimpleNameSyntax methodNameSyntax) { SimpleNameSyntax className = memberAccess.Expression as SimpleNameSyntax; if (className == null && memberAccess.Expression is MemberAccessExpressionSyntax classMemberAccess) { className = classMemberAccess.Name as SimpleNameSyntax; } if (className != null && ValidContractClasses.Contains(className.Identifier.ValueText)) { SimpleNameSyntax methodName = methodNameSyntax; NameSyntax genericExceptionType = null; if (methodNameSyntax is GenericNameSyntax genericName && genericName.TypeArgumentList.Arguments.Count == 1) { genericExceptionType = genericName.TypeArgumentList.Arguments[0] as NameSyntax; } ExpressionSyntax condition = invocation.ArgumentList.Arguments[0].Expression; ExpressionSyntax message = null; ExpressionSyntax conditionString = null; if (invocation.ArgumentList.Arguments.Count >= 2) { if (invocation.ArgumentList.Arguments[1].NameColon != null) { if (invocation.ArgumentList.Arguments[1].NameColon.Name.Identifier.ValueText == "conditionString") { conditionString = invocation.ArgumentList.Arguments[1].Expression; } else { message = invocation.ArgumentList.Arguments[1].Expression; } } else { message = invocation.ArgumentList.Arguments[1].Expression; } } if (invocation.ArgumentList.Arguments.Count == 3) { if (invocation.ArgumentList.Arguments[2].NameColon != null) { if (invocation.ArgumentList.Arguments[2].NameColon.Name.Identifier.ValueText == "message" || invocation.ArgumentList.Arguments[2].NameColon.Name.Identifier.ValueText == "userMessage") { message = invocation.ArgumentList.Arguments[2].Expression; } else { conditionString = invocation.ArgumentList.Arguments[2].Expression; } } else { conditionString = invocation.ArgumentList.Arguments[2].Expression; } } if (className != null && methodName != null && condition != null) { invocationInfo = new ContractInvocationInfo(className, methodName, genericExceptionType, condition, message, conditionString, invocation.ArgumentList); return(true); } } } invocationInfo = null; return(false); }
#pragma warning disable AvoidAsyncSuffix // Avoid Async suffix internal static MemberAccessExpressionSyntax MemberAccess(IReadOnlyList <string> qualifiers, SimpleNameSyntax simpleName) { if (qualifiers == null) { throw new ArgumentNullException(nameof(qualifiers)); } if (simpleName == null) { throw new ArgumentNullException(nameof(simpleName)); } if (qualifiers.Count == 0) { throw new ArgumentException("At least one qualifier required."); } ExpressionSyntax result = SyntaxFactory.IdentifierName(qualifiers[0]); for (int i = 1; i < qualifiers.Count; i++) { var rightSide = SyntaxFactory.IdentifierName(qualifiers[i]); result = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, result, rightSide); } return(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, result, simpleName)); }
public static ExpressionSyntax CreateExpressionWithNewName(InvocationExpressionSyntax invocation, SimpleNameSyntax nameToCheck) { var otherExpression = invocation.Expression.IsKind(SyntaxKind.MemberBindingExpression) ? (ExpressionSyntax)((MemberBindingExpressionSyntax)invocation.Expression).WithName(nameToCheck).WithAdditionalAnnotations(speculativeAnnotation) //avoid this, already checked before: if (invocation.Expression.IsKind(SyntaxKind.SimpleMemberAccessExpression)): : ((MemberAccessExpressionSyntax)invocation.Expression).WithName(nameToCheck).WithAdditionalAnnotations(speculativeAnnotation); return(otherExpression); }
protected override async Task <Solution> GetChangedSolutionAsync(CancellationToken cancellationToken) { var document = this.document; var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); // Find the synchronously blocking call member, // and bookmark it so we can find it again after some mutations have taken place. var syncAccessBookmark = new SyntaxAnnotation(); SimpleNameSyntax syncMethodName = (SimpleNameSyntax)root.FindNode(this.diagnostic.Location.SourceSpan); if (syncMethodName == null) { var syncMemberAccess = root.FindNode(this.diagnostic.Location.SourceSpan).FirstAncestorOrSelf <MemberAccessExpressionSyntax>(); syncMethodName = syncMemberAccess.Name; } // When we give the Document a modified SyntaxRoot, yet another is created. So we first assign it to the Document, // then we query for the SyntaxRoot from the Document. document = document.WithSyntaxRoot( root.ReplaceNode(syncMethodName, syncMethodName.WithAdditionalAnnotations(syncAccessBookmark))); root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); syncMethodName = (SimpleNameSyntax)root.GetAnnotatedNodes(syncAccessBookmark).Single(); // We'll need the semantic model later. But because we've annotated a node, that changes the SyntaxRoot // and that renders the default semantic model broken (even though we've already updated the document's SyntaxRoot?!). // So after acquiring the semantic model, update it with the new method body. var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var originalAnonymousMethodContainerIfApplicable = syncMethodName.FirstAncestorOrSelf <AnonymousFunctionExpressionSyntax>(); var originalMethodDeclaration = syncMethodName.FirstAncestorOrSelf <MethodDeclarationSyntax>(); // Ensure that the method or anonymous delegate is using the async keyword. MethodDeclarationSyntax updatedMethod; if (originalAnonymousMethodContainerIfApplicable != null) { updatedMethod = originalMethodDeclaration.ReplaceNode( originalAnonymousMethodContainerIfApplicable, originalAnonymousMethodContainerIfApplicable.MakeMethodAsync(semanticModel, cancellationToken)); } else { (document, updatedMethod) = await originalMethodDeclaration.MakeMethodAsync(document, cancellationToken).ConfigureAwait(false); semanticModel = null; // out-dated } if (updatedMethod != originalMethodDeclaration) { // Re-discover our synchronously blocking member. syncMethodName = (SimpleNameSyntax)updatedMethod.GetAnnotatedNodes(syncAccessBookmark).Single(); } var syncExpression = (ExpressionSyntax)syncMethodName.FirstAncestorOrSelf <InvocationExpressionSyntax>() ?? syncMethodName.FirstAncestorOrSelf <MemberAccessExpressionSyntax>(); ExpressionSyntax awaitExpression; if (this.AlternativeAsyncMethod != string.Empty) { // Replace the member being called and await the invocation expression. var asyncMethodName = syncMethodName.WithIdentifier(SyntaxFactory.Identifier(this.diagnostic.Properties[AsyncMethodKeyName])); awaitExpression = SyntaxFactory.AwaitExpression(syncExpression.ReplaceNode(syncMethodName, asyncMethodName)); if (!(syncExpression.Parent is ExpressionStatementSyntax)) { awaitExpression = SyntaxFactory.ParenthesizedExpression(awaitExpression) .WithAdditionalAnnotations(Simplifier.Annotation); } } else { // Remove the member being accessed that causes a synchronous block and simply await the object. var syncMemberAccess = syncMethodName.FirstAncestorOrSelf <MemberAccessExpressionSyntax>(); var syncMemberStrippedExpression = syncMemberAccess.Expression; // Special case a common pattern of calling task.GetAwaiter().GetResult() and remove both method calls. var expressionMethodCall = (syncMemberStrippedExpression as InvocationExpressionSyntax)?.Expression as MemberAccessExpressionSyntax; if (expressionMethodCall?.Name.Identifier.Text == nameof(Task.GetAwaiter)) { syncMemberStrippedExpression = expressionMethodCall.Expression; } awaitExpression = SyntaxFactory.AwaitExpression(syncMemberStrippedExpression); } updatedMethod = updatedMethod .ReplaceNode(syncExpression, awaitExpression); var newRoot = root.ReplaceNode(originalMethodDeclaration, updatedMethod); var newDocument = document.WithSyntaxRoot(newRoot); return(newDocument.Project.Solution); }
private static CompilationUnitSyntax ReplaceStaticCallWithExtionMethodCall(CompilationUnitSyntax root, InvocationExpressionSyntax staticInvocationExpression, ExpressionSyntax sourceExpression, SimpleNameSyntax methodName, ArgumentListSyntax argumentList) { var extensionInvocationExpression = CreateInvocationExpression(sourceExpression, methodName, argumentList) .WithLeadingTrivia(staticInvocationExpression.GetLeadingTrivia()); return(root.ReplaceNode(staticInvocationExpression, extensionInvocationExpression)); }
public static InvocationExpressionSyntax CreateInvocationExpression(ExpressionSyntax sourceExpression, SimpleNameSyntax methodName, ArgumentListSyntax argumentList) => SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, sourceExpression, methodName), argumentList);
protected AbstractFunctionDataReference(TData data, ReferenceLocation referenceLocation, SimpleNameSyntax referenceNameNode, IMethodSymbol referenceSymbol, FunctionData referenceFunctionData, bool insideMethodBody) : base(data, referenceLocation, referenceNameNode, referenceSymbol, referenceFunctionData) { ReferenceFunctionData = referenceFunctionData; InsideMethodBody = insideMethodBody; }
/// <summary> /// Updates the given SimpleNameSyntax node with the given identifier token. /// This function is a wrapper that calls WithIdentifier on derived syntax nodes. /// </summary> /// <param name="simpleName"></param> /// <param name="identifier"></param> /// <returns>The given simple name updated with the given identifier.</returns> public static SimpleNameSyntax WithIdentifier(this SimpleNameSyntax simpleName, SyntaxToken identifier) { return(simpleName.Kind == SyntaxKind.IdentifierName ? (SimpleNameSyntax)((IdentifierNameSyntax)simpleName).WithIdentifier(identifier) : (SimpleNameSyntax)((GenericNameSyntax)simpleName).WithIdentifier(identifier)); }
private static Expression Create(ExpressionNodeInfo info, ExpressionSyntax expression, SimpleNameSyntax name) { if (IsDynamic(info.Context, expression)) { var expr = new MemberAccess(info.SetKind(ExprKind.DYNAMIC_MEMBER_ACCESS), expression, null); info.Context.TrapWriter.Writer.dynamic_member_name(expr, name.Identifier.Text); return(expr); } var target = info.SymbolInfo; if (target.CandidateReason == CandidateReason.OverloadResolutionFailure) { // Roslyn workaround. Even if we can't resolve a method, we know it's a method. return(Create(info.Context, expression, info.Parent, info.Child)); } var symbol = target.Symbol ?? info.Context.GetSymbolInfo(name).Symbol; if (symbol is null && target.CandidateSymbols.Length >= 1) { // Pick the first symbol. This could occur for something like `nameof(Foo.Bar)` // where `Bar` is a method group. Technically, we don't know which symbol is accessed. symbol = target.CandidateSymbols[0]; } if (symbol is null) { info.Context.ModelError(info.Node, "Failed to determine symbol for member access"); // Default to property access - this can still give useful results but // the target of the expression should be checked in QL. return(new MemberAccess(info.SetKind(ExprKind.PROPERTY_ACCESS), expression, symbol)); } ExprKind kind; switch (symbol.Kind) { case SymbolKind.Property: kind = ExprKind.PROPERTY_ACCESS; break; case SymbolKind.Method: kind = ExprKind.METHOD_ACCESS; break; case SymbolKind.Field: kind = ExprKind.FIELD_ACCESS; break; case SymbolKind.NamedType: return(TypeAccess.Create(info)); case SymbolKind.Event: kind = ExprKind.EVENT_ACCESS; break; case SymbolKind.Namespace: kind = ExprKind.NAMESPACE_ACCESS; break; default: info.Context.ModelError(info.Node, "Unhandled symbol for member access"); kind = ExprKind.UNKNOWN; break; } return(new MemberAccess(info.SetKind(kind), expression, symbol)); }
private static async Task <Document> GenerateInterfaceImplementationAsync(Document document, SimpleBaseTypeSyntax baseTypeSyntax, CancellationToken cancellationToken) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken); SimpleNameSyntax sns = (baseTypeSyntax.Type as SimpleNameSyntax) ?? (baseTypeSyntax.Type as QualifiedNameSyntax).Right; var interfaceSymbol = semanticModel.GetSymbolInfo(sns).Symbol as INamedTypeSymbol; if (interfaceSymbol == null || interfaceSymbol.TypeKind != TypeKind.Interface) { return(document); } var originalClassDefinitionSyntax = (ClassDeclarationSyntax)baseTypeSyntax.Parent.Parent; ClassDeclarationSyntax modifiedClassDefinitionSyntax = null; if (interfaceSymbol.Name == "IObjectMapper" && interfaceSymbol.TypeArguments.Length == 1) { var sourceClassSymbol = semanticModel.GetDeclaredSymbol(originalClassDefinitionSyntax); var targetClassSymbol = interfaceSymbol.TypeArguments[0].OriginalDefinition as INamedTypeSymbol; if (sourceClassSymbol == null || targetClassSymbol == null) { return(document); } var matchedProperties = RetrieveMatchedProperties(sourceClassSymbol, targetClassSymbol); var updatedMethods = new Dictionary <MethodDeclarationSyntax, MethodDeclarationSyntax>(); var addedMethods = new List <MethodDeclarationSyntax>(); foreach (IMethodSymbol member in interfaceSymbol.GetMembers().Where(x => x.Kind == SymbolKind.Method)) { var method = sourceClassSymbol.FindImplementationForInterfaceMember(member) as IMethodSymbol; MethodDeclarationSyntax methodSyntax = null; if (method != null) { methodSyntax = await method.DeclaringSyntaxReferences[0].GetSyntaxAsync(cancellationToken) as MethodDeclarationSyntax; var newMethodSyntax = methodSyntax.WithBody(GenerateMethodBody(member, matchedProperties, semanticModel, originalClassDefinitionSyntax.Span.End - 1)); updatedMethods.Add(methodSyntax, newMethodSyntax); } else { methodSyntax = GenerateMethodImplementation(member, semanticModel, originalClassDefinitionSyntax.Span.End - 1). WithBody(GenerateMethodBody(member, matchedProperties, semanticModel, originalClassDefinitionSyntax.Span.End - 1)); addedMethods.Add(methodSyntax); } } modifiedClassDefinitionSyntax = originalClassDefinitionSyntax.ReplaceNodes(updatedMethods.Keys.AsEnumerable(), (n1, n2) => updatedMethods[n1]).AddMembers(addedMethods.ToArray()); } else if (interfaceSymbol.Name == "IObjectMapperAdapter" && interfaceSymbol.TypeArguments.Length == 2) { var adapterClassSymbol = semanticModel.GetDeclaredSymbol(originalClassDefinitionSyntax); var sourceClassSymbol = interfaceSymbol.TypeArguments[0].OriginalDefinition as INamedTypeSymbol; var targetClassSymbol = interfaceSymbol.TypeArguments[1].OriginalDefinition as INamedTypeSymbol; if (sourceClassSymbol == null || targetClassSymbol == null) { return(document); } var matchedProperties = RetrieveMatchedProperties(sourceClassSymbol, targetClassSymbol); var updatedMethods = new Dictionary <MethodDeclarationSyntax, MethodDeclarationSyntax>(); var addedMethods = new List <MethodDeclarationSyntax>(); foreach (IMethodSymbol member in interfaceSymbol.GetMembers().Where(x => x.Kind == SymbolKind.Method)) { var matchingPropertyList = matchedProperties; // check if we have to switch matched properties if (member.Parameters.Length == 2 && !interfaceSymbol.TypeArguments[0].Equals(member.Parameters[0].Type)) { matchingPropertyList = matchingPropertyList.Select(x => new MatchedPropertySymbols { Source = x.Target, Target = x.Source }); } var method = adapterClassSymbol.FindImplementationForInterfaceMember(member) as IMethodSymbol; MethodDeclarationSyntax methodSyntax = null; if (method != null) { methodSyntax = await method.DeclaringSyntaxReferences[0].GetSyntaxAsync(cancellationToken) as MethodDeclarationSyntax; var newMethodSyntax = methodSyntax.WithBody(GenerateMethodBody(member, matchingPropertyList, semanticModel, originalClassDefinitionSyntax.Span.End - 1)); updatedMethods.Add(methodSyntax, newMethodSyntax); } else { methodSyntax = GenerateMethodImplementation(member, semanticModel, originalClassDefinitionSyntax.Span.End - 1). WithBody(GenerateMethodBody(member, matchingPropertyList, semanticModel, originalClassDefinitionSyntax.Span.End - 1)); addedMethods.Add(methodSyntax); } } modifiedClassDefinitionSyntax = originalClassDefinitionSyntax.ReplaceNodes(updatedMethods.Keys.AsEnumerable(), (n1, n2) => updatedMethods[n1]).AddMembers(addedMethods.ToArray()); } if (modifiedClassDefinitionSyntax == null) { return(document); } // replace root and return modified document var root = await document.GetSyntaxRootAsync(cancellationToken); var newRoot = root.ReplaceNode(originalClassDefinitionSyntax, modifiedClassDefinitionSyntax); var newDocument = document.WithSyntaxRoot(newRoot); return(newDocument); }
private static void AnalyzeSimpleMemberAccessExpression(SyntaxNodeAnalysisContext context) { var memberAccessExpression = (MemberAccessExpressionSyntax)context.Node; SimpleNameSyntax name = memberAccessExpression.Name; switch (name) { case IdentifierNameSyntax identifierName: { switch (identifierName.Identifier.ValueText) { case "Start": { ExpressionSyntax expression = memberAccessExpression.Expression; if (!expression.IsKind(SyntaxKind.SimpleMemberAccessExpression)) { break; } ISymbol symbol = context.SemanticModel.GetSymbol(memberAccessExpression, context.CancellationToken); if (symbol == null) { break; } if (!symbol.ContainingType.HasMetadataName(RoslynMetadataNames.Microsoft_CodeAnalysis_Text_TextSpan)) { break; } var memberAccess2 = (MemberAccessExpressionSyntax)expression; SimpleNameSyntax name2 = memberAccess2.Name; if (!(name2 is IdentifierNameSyntax identifierName2)) { break; } if (!string.Equals(identifierName2.Identifier.ValueText, "Span", StringComparison.Ordinal)) { break; } ISymbol symbol2 = context.SemanticModel.GetSymbol(expression, context.CancellationToken); if (symbol2 == null) { break; } if (!symbol2.ContainingType.HasMetadataName(RoslynMetadataNames.Microsoft_CodeAnalysis_SyntaxNode)) { break; } DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UsePropertySyntaxNodeSpanStart, memberAccessExpression); break; } case "Count": { CallAnyInsteadOfUsingCount(); break; } } break; } } void CallAnyInsteadOfUsingCount() { SyntaxNode expression = memberAccessExpression.WalkUpParentheses(); SyntaxNode parent = expression.Parent; if (!parent.IsKind(SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression, SyntaxKind.GreaterThanExpression)) { return; } BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)parent); if (!binaryExpressionInfo.Success) { return; } ExpressionSyntax otherExpression = (expression == binaryExpressionInfo.Left) ? binaryExpressionInfo.Right : binaryExpressionInfo.Left; if (!otherExpression.IsKind(SyntaxKind.NumericLiteralExpression)) { return; } var numericLiteralExpression = (LiteralExpressionSyntax)otherExpression; if (numericLiteralExpression.Token.ValueText != "0") { return; } ISymbol symbol = context.SemanticModel.GetSymbol(memberAccessExpression, context.CancellationToken); if (symbol?.Kind != SymbolKind.Property || symbol.IsStatic || symbol.DeclaredAccessibility != Accessibility.Public || !RoslynSymbolUtility.IsList(symbol.ContainingType.OriginalDefinition)) { return; } TextSpan span = (memberAccessExpression == binaryExpressionInfo.Left) ? TextSpan.FromBounds(name.SpanStart, numericLiteralExpression.Span.End) : TextSpan.FromBounds(numericLiteralExpression.SpanStart, name.Span.End); DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.CallAnyInsteadOfAccessingCount, Location.Create(memberAccessExpression.SyntaxTree, span)); } }
public override LookupResult Lookup(SimpleNameSyntax name, Package fromPackage) { throw new NotImplementedException(); }
internal static MemberAccessExpressionSyntax QualifyWithThis(this SimpleNameSyntax simpleName, bool simplifiable = true) { return(SimpleMemberAccessExpression(ThisExpression(), simpleName).WithSimplifierAnnotationIf(simplifiable)); }