private ExpressionSyntax TryAddTypeArgumentToIdentifierName(ExpressionSyntax newNode, ISymbol symbol) { if (newNode.Kind() == SyntaxKind.IdentifierName && symbol.Kind == SymbolKind.Method) { if (((IMethodSymbol)symbol).TypeArguments.Length != 0) { var typeArguments = ((IMethodSymbol)symbol).TypeArguments; var genericName = SyntaxFactory.GenericName( ((IdentifierNameSyntax)newNode).Identifier, SyntaxFactory.TypeArgumentList( SyntaxFactory.SeparatedList( typeArguments.Select(p => SyntaxFactory.ParseTypeName(p.ToDisplayParts(s_typeNameFormatWithGenerics).ToDisplayString()))))) .WithLeadingTrivia(newNode.GetLeadingTrivia()) .WithTrailingTrivia(newNode.GetTrailingTrivia()) .WithAdditionalAnnotations(Simplifier.Annotation); genericName = newNode.CopyAnnotationsTo(genericName); return(genericName); } } return(newNode); }
private ExpressionSyntax FullyQualifyIdentifierName( ISymbol symbol, ExpressionSyntax rewrittenNode, ExpressionSyntax originalNode, bool replaceNode, bool isInsideCref, bool omitLeftHandSide) { Debug.Assert(!replaceNode || rewrittenNode.Kind() == SyntaxKind.IdentifierName); //// TODO: use and expand Generate*Syntax(isymbol) to not depend on symbol display any more. //// See GenerateExpressionSyntax(); var result = rewrittenNode; // only if this symbol has a containing type or namespace there is work for us to do. if (replaceNode || symbol.ContainingType != null || symbol.ContainingNamespace != null) { ImmutableArray<SymbolDisplayPart> displayParts; ExpressionSyntax left = null; // we either need to create an AliasQualifiedName if the symbol is directly contained in the global namespace, // otherwise it a QualifiedName. if (!replaceNode && symbol.ContainingType == null && symbol.ContainingNamespace.IsGlobalNamespace) { return rewrittenNode.CopyAnnotationsTo( SyntaxFactory.AliasQualifiedName( SyntaxFactory.IdentifierName(SyntaxFactory.Token(SyntaxKind.GlobalKeyword)), (SimpleNameSyntax)rewrittenNode.WithLeadingTrivia(null)) .WithLeadingTrivia(rewrittenNode.GetLeadingTrivia())); } displayParts = replaceNode ? symbol.ToDisplayParts(s_typeNameFormatWithGenerics) : (symbol.ContainingType ?? (ISymbol)symbol.ContainingNamespace).ToDisplayParts(s_typeNameFormatWithGenerics); rewrittenNode = TryAddTypeArgumentToIdentifierName(rewrittenNode, symbol); // Replaces the '<' token with the '{' token since we are inside crefs rewrittenNode = TryReplaceAngleBracesWithCurlyBraces(rewrittenNode, isInsideCref); result = rewrittenNode; if (!omitLeftHandSide) { left = SyntaxFactory.ParseTypeName(displayParts.ToDisplayString()); // Replaces the '<' token with the '{' token since we are inside crefs left = TryReplaceAngleBracesWithCurlyBraces(left, isInsideCref); if (replaceNode) { return left .WithLeadingTrivia(rewrittenNode.GetLeadingTrivia()) .WithTrailingTrivia(rewrittenNode.GetTrailingTrivia()); } // now create syntax for the combination of left and right syntax, or a simple replacement in case of an identifier var parent = originalNode.Parent; var leadingTrivia = rewrittenNode.GetLeadingTrivia(); rewrittenNode = rewrittenNode.WithLeadingTrivia(null); switch (parent.Kind()) { case SyntaxKind.QualifiedName: var qualifiedParent = (QualifiedNameSyntax)parent; result = rewrittenNode.CopyAnnotationsTo( SyntaxFactory.QualifiedName( (NameSyntax)left, (SimpleNameSyntax)rewrittenNode)); break; case SyntaxKind.SimpleMemberAccessExpression: var memberAccessParent = (MemberAccessExpressionSyntax)parent; result = rewrittenNode.CopyAnnotationsTo( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, left, (SimpleNameSyntax)rewrittenNode)); break; default: Debug.Assert(rewrittenNode is SimpleNameSyntax); if (SyntaxFacts.IsInNamespaceOrTypeContext(originalNode)) { var right = (SimpleNameSyntax)rewrittenNode; result = rewrittenNode.CopyAnnotationsTo(SyntaxFactory.QualifiedName((NameSyntax)left, right.WithAdditionalAnnotations(Simplifier.SpecialTypeAnnotation))); } else if (originalNode.Parent is CrefSyntax) { var right = (SimpleNameSyntax)rewrittenNode; result = rewrittenNode.CopyAnnotationsTo(SyntaxFactory.QualifiedName((NameSyntax)left, right)); } else { result = rewrittenNode.CopyAnnotationsTo( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, left, (SimpleNameSyntax)rewrittenNode)); } break; } result = result.WithLeadingTrivia(leadingTrivia); } } return result; }
private ExpressionSyntax TryAddTypeArgumentToIdentifierName(ExpressionSyntax newNode, ISymbol symbol) { if (newNode.Kind() == SyntaxKind.IdentifierName && symbol.Kind == SymbolKind.Method) { if (((IMethodSymbol)symbol).TypeArguments.Length != 0) { var typeArguments = ((IMethodSymbol)symbol).TypeArguments; if (!typeArguments.Any(t => t.ContainsAnonymousType())) { var genericName = SyntaxFactory.GenericName( ((IdentifierNameSyntax)newNode).Identifier, SyntaxFactory.TypeArgumentList( SyntaxFactory.SeparatedList( typeArguments.Select(p => SyntaxFactory.ParseTypeName(p.ToDisplayParts(s_typeNameFormatWithGenerics).ToDisplayString()))))) .WithLeadingTrivia(newNode.GetLeadingTrivia()) .WithTrailingTrivia(newNode.GetTrailingTrivia()) .WithAdditionalAnnotations(Simplifier.Annotation); genericName = newNode.CopyAnnotationsTo(genericName); return genericName; } } } return newNode; }
private ExpressionSyntax FullyQualifyIdentifierName( ISymbol symbol, ExpressionSyntax rewrittenNode, ExpressionSyntax originalNode, bool replaceNode, bool isInsideCref, bool omitLeftHandSide) { Debug.Assert(!replaceNode || rewrittenNode.Kind() == SyntaxKind.IdentifierName); //// TODO: use and expand Generate*Syntax(isymbol) to not depend on symbol display any more. //// See GenerateExpressionSyntax(); var result = rewrittenNode; // only if this symbol has a containing type or namespace there is work for us to do. if (replaceNode || symbol.ContainingType != null || symbol.ContainingNamespace != null) { ImmutableArray <SymbolDisplayPart> displayParts; ExpressionSyntax left = null; // we either need to create an AliasQualifiedName if the symbol is directly contained in the global namespace, // otherwise it a QualifiedName. if (!replaceNode && symbol.ContainingType == null && symbol.ContainingNamespace.IsGlobalNamespace) { return(rewrittenNode.CopyAnnotationsTo( SyntaxFactory.AliasQualifiedName( SyntaxFactory.IdentifierName(SyntaxFactory.Token(SyntaxKind.GlobalKeyword)), (SimpleNameSyntax)rewrittenNode.WithLeadingTrivia(null)) .WithLeadingTrivia(rewrittenNode.GetLeadingTrivia()))); } displayParts = replaceNode ? symbol.ToDisplayParts(s_typeNameFormatWithGenerics) : ((ISymbol)symbol.ContainingType ?? (ISymbol)symbol.ContainingNamespace).ToDisplayParts(s_typeNameFormatWithGenerics); rewrittenNode = TryAddTypeArgumentToIdentifierName(rewrittenNode, symbol); // Replaces the '<' token with the '{' token since we are inside crefs rewrittenNode = TryReplaceAngleBracesWithCurlyBraces(rewrittenNode, isInsideCref); result = rewrittenNode; if (!omitLeftHandSide) { left = SyntaxFactory.ParseTypeName(displayParts.ToDisplayString()); // Replaces the '<' token with the '{' token since we are inside crefs left = TryReplaceAngleBracesWithCurlyBraces(left, isInsideCref); if (replaceNode) { return(left .WithLeadingTrivia(rewrittenNode.GetLeadingTrivia()) .WithTrailingTrivia(rewrittenNode.GetTrailingTrivia())); } // now create syntax for the combination of left and right syntax, or a simple replacement in case of an identifier var parent = originalNode.Parent; var leadingTrivia = rewrittenNode.GetLeadingTrivia(); rewrittenNode = rewrittenNode.WithLeadingTrivia(null); switch (parent.Kind()) { case SyntaxKind.QualifiedName: var qualifiedParent = (QualifiedNameSyntax)parent; result = rewrittenNode.CopyAnnotationsTo( SyntaxFactory.QualifiedName( (NameSyntax)left, (SimpleNameSyntax)rewrittenNode)); break; case SyntaxKind.SimpleMemberAccessExpression: var memberAccessParent = (MemberAccessExpressionSyntax)parent; result = rewrittenNode.CopyAnnotationsTo( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, left, (SimpleNameSyntax)rewrittenNode)); break; default: Debug.Assert(rewrittenNode is SimpleNameSyntax); if (SyntaxFacts.IsInNamespaceOrTypeContext(originalNode)) { var right = (SimpleNameSyntax)rewrittenNode; result = rewrittenNode.CopyAnnotationsTo(SyntaxFactory.QualifiedName((NameSyntax)left, right.WithAdditionalAnnotations(Simplifier.SpecialTypeAnnotation))); } else if (originalNode.Parent is CrefSyntax) { var right = (SimpleNameSyntax)rewrittenNode; result = rewrittenNode.CopyAnnotationsTo(SyntaxFactory.QualifiedName((NameSyntax)left, right)); } else { result = rewrittenNode.CopyAnnotationsTo( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, left, (SimpleNameSyntax)rewrittenNode)); } break; } result = result.WithLeadingTrivia(leadingTrivia); } } return(result); }
private ExpressionSyntax VisitSimpleName(SimpleNameSyntax rewrittenSimpleName, SimpleNameSyntax originalSimpleName) { _cancellationToken.ThrowIfCancellationRequested(); // if this is "var", then do not process further if (originalSimpleName.IsVar) { return(rewrittenSimpleName); } var identifier = rewrittenSimpleName.Identifier; ExpressionSyntax newNode = rewrittenSimpleName; var isInsideCref = originalSimpleName.AncestorsAndSelf(ascendOutOfTrivia: true).Any(n => n is CrefSyntax); //// //// 1. if this identifier is an alias, we'll expand it here and replace the node completely. //// if (!SyntaxFacts.IsAliasQualifier(originalSimpleName)) { var aliasInfo = _semanticModel.GetAliasInfo(originalSimpleName, _cancellationToken); if (aliasInfo != null) { var aliasTarget = aliasInfo.Target; if (aliasTarget.IsNamespace() && ((INamespaceSymbol)aliasTarget).IsGlobalNamespace) { return(rewrittenSimpleName); } // if the enclosing expression is a typeof expression that already contains open type we cannot // we need to insert an open type as well. var typeOfExpression = originalSimpleName.GetAncestor <TypeOfExpressionSyntax>(); if (typeOfExpression != null && IsTypeOfUnboundGenericType(_semanticModel, typeOfExpression)) { aliasTarget = ((INamedTypeSymbol)aliasTarget).ConstructUnboundGenericType(); } // the expanded form replaces the current identifier name. var replacement = FullyQualifyIdentifierName( aliasTarget, newNode, originalSimpleName, replaceNode: true, isInsideCref: isInsideCref, omitLeftHandSide: false) .WithAdditionalAnnotations(Simplifier.Annotation); // We replace the simple name completely, so we can't continue and rename the token // with a RenameLocationAnnotation. // There's also no way of removing annotations, so we just add a DoNotRenameAnnotation. if (replacement.Kind() == SyntaxKind.AliasQualifiedName) { var qualifiedReplacement = (AliasQualifiedNameSyntax)replacement; var newIdentifier = identifier.CopyAnnotationsTo(qualifiedReplacement.Name.Identifier); if (_annotationForReplacedAliasIdentifier != null) { newIdentifier = newIdentifier.WithAdditionalAnnotations(_annotationForReplacedAliasIdentifier); } var aliasAnnotationInfo = AliasAnnotation.Create(aliasInfo.Name); newIdentifier = newIdentifier.WithAdditionalAnnotations(aliasAnnotationInfo); replacement = replacement.ReplaceNode( qualifiedReplacement.Name, qualifiedReplacement.Name.WithIdentifier(newIdentifier)); replacement = newNode.CopyAnnotationsTo(replacement); var firstReplacementToken = replacement.GetFirstToken(true, false, true, true); var firstOriginalToken = originalSimpleName.GetFirstToken(true, false, true, true); SyntaxToken tokenWithLeadingWhitespace; if (TryAddLeadingElasticTriviaIfNecessary(firstReplacementToken, firstOriginalToken, out tokenWithLeadingWhitespace)) { replacement = replacement.ReplaceToken(firstOriginalToken, tokenWithLeadingWhitespace); } replacement = AppendElasticTriviaIfNecessary(replacement, originalSimpleName); return(replacement); } if (replacement.Kind() == SyntaxKind.QualifiedName) { var qualifiedReplacement = (QualifiedNameSyntax)replacement; var newIdentifier = identifier.CopyAnnotationsTo(qualifiedReplacement.Right.Identifier); if (_annotationForReplacedAliasIdentifier != null) { newIdentifier = newIdentifier.WithAdditionalAnnotations(_annotationForReplacedAliasIdentifier); } var aliasAnnotationInfo = AliasAnnotation.Create(aliasInfo.Name); newIdentifier = newIdentifier.WithAdditionalAnnotations(aliasAnnotationInfo); replacement = replacement.ReplaceNode( qualifiedReplacement.Right, qualifiedReplacement.Right.WithIdentifier(newIdentifier)); replacement = newNode.CopyAnnotationsTo(replacement); replacement = AppendElasticTriviaIfNecessary(replacement, originalSimpleName); return(replacement); } throw new NotImplementedException(); } } var symbol = _semanticModel.GetSymbolInfo(originalSimpleName.Identifier).Symbol; if (symbol == null) { return(newNode); } var typeArgumentSymbols = TypeArgumentSymbolsPresentInName(originalSimpleName); var omitLeftSideOfExpression = false; // Check to see if the type Arguments in the resultant Symbol is recursively defined. if (IsTypeArgumentDefinedRecursive(symbol, typeArgumentSymbols, enterContainingSymbol: true)) { if (symbol.ContainingSymbol.Equals(symbol.OriginalDefinition.ContainingSymbol) && symbol.Kind == SymbolKind.Method && ((IMethodSymbol)symbol).IsStatic) { if (IsTypeArgumentDefinedRecursive(symbol, typeArgumentSymbols, enterContainingSymbol: false)) { return(newNode); } else { omitLeftSideOfExpression = true; } } else { return(newNode); } } if (IsInvocationWithDynamicArguments(originalSimpleName, _semanticModel)) { return(newNode); } //// //// 2. If it's an attribute, make sure the identifier matches the attribute's class name. //// if (originalSimpleName.GetAncestor <AttributeSyntax>() != null) { if (symbol.IsConstructor() && symbol.ContainingType?.IsAttribute() == true) { symbol = symbol.ContainingType; var name = symbol.Name; Debug.Assert(name.StartsWith(originalSimpleName.Identifier.ValueText, StringComparison.Ordinal)); // if the user already used the Attribute suffix in the attribute, we'll maintain it. if (identifier.ValueText == name && name.EndsWith("Attribute", StringComparison.Ordinal)) { identifier = identifier.WithAdditionalAnnotations(SimplificationHelpers.DontSimplifyAnnotation); } identifier = identifier.CopyAnnotationsTo(SyntaxFactory.VerbatimIdentifier(identifier.LeadingTrivia, name, name, identifier.TrailingTrivia)); } } //// //// 3. Always try to escape keyword identifiers //// identifier = TryEscapeIdentifierToken(identifier, originalSimpleName, _semanticModel).WithAdditionalAnnotations(Simplifier.Annotation); if (identifier != rewrittenSimpleName.Identifier) { switch (newNode.Kind()) { case SyntaxKind.IdentifierName: case SyntaxKind.GenericName: newNode = ((SimpleNameSyntax)newNode).WithIdentifier(identifier); break; default: throw new NotImplementedException(); } } var parent = originalSimpleName.Parent; // do not complexify further for location where only simple names are allowed if (parent is MemberDeclarationSyntax || parent is MemberBindingExpressionSyntax || originalSimpleName.GetAncestor <NameEqualsSyntax>() != null || (parent is MemberAccessExpressionSyntax && parent.Kind() != SyntaxKind.SimpleMemberAccessExpression) || ((parent.Kind() == SyntaxKind.SimpleMemberAccessExpression || parent.Kind() == SyntaxKind.NameMemberCref) && originalSimpleName.IsRightSideOfDot()) || (parent.Kind() == SyntaxKind.QualifiedName && originalSimpleName.IsRightSideOfQualifiedName()) || (parent.Kind() == SyntaxKind.AliasQualifiedName)) { return(TryAddTypeArgumentToIdentifierName(newNode, symbol)); } //// //// 4. If this is a standalone identifier or the left side of a qualified name or member access try to fully qualify it //// // we need to treat the constructor as type name, so just get the containing type. if (symbol.IsConstructor() && (parent.Kind() == SyntaxKind.ObjectCreationExpression || parent.Kind() == SyntaxKind.NameMemberCref)) { symbol = symbol.ContainingType; } // if it's a namespace or type name, fully qualify it. if (symbol.Kind == SymbolKind.NamedType || symbol.Kind == SymbolKind.Namespace) { var replacement = FullyQualifyIdentifierName( (INamespaceOrTypeSymbol)symbol, newNode, originalSimpleName, replaceNode: false, isInsideCref: isInsideCref, omitLeftHandSide: omitLeftSideOfExpression) .WithAdditionalAnnotations(Simplifier.Annotation); replacement = AppendElasticTriviaIfNecessary(replacement, originalSimpleName); return(replacement); } // if it's a member access, we're fully qualifying the left side and make it a member access. if (symbol.Kind == SymbolKind.Method || symbol.Kind == SymbolKind.Field || symbol.Kind == SymbolKind.Property) { if (symbol.IsStatic || originalSimpleName.IsParentKind(SyntaxKind.NameMemberCref) || _semanticModel.SyntaxTree.IsNameOfContext(originalSimpleName.SpanStart, _semanticModel, _cancellationToken)) { newNode = FullyQualifyIdentifierName( symbol, newNode, originalSimpleName, replaceNode: false, isInsideCref: isInsideCref, omitLeftHandSide: omitLeftSideOfExpression); } else { if (!IsPropertyNameOfObjectInitializer(originalSimpleName)) { ExpressionSyntax left; // Assumption here is, if the enclosing and containing types are different then there is Inheritence relationship if (_semanticModel.GetEnclosingNamedType(originalSimpleName.SpanStart, _cancellationToken) != symbol.ContainingType) { left = SyntaxFactory.BaseExpression(); } else { left = SyntaxFactory.ThisExpression(); } var identifiersLeadingTrivia = newNode.GetLeadingTrivia(); newNode = TryAddTypeArgumentToIdentifierName(newNode, symbol); newNode = newNode.CopyAnnotationsTo( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, left, (SimpleNameSyntax)newNode.WithLeadingTrivia(null)) .WithLeadingTrivia(identifiersLeadingTrivia)); } } } var result = newNode.WithAdditionalAnnotations(Simplifier.Annotation); result = AppendElasticTriviaIfNecessary(result, originalSimpleName); return(result); }