public static IAliasSymbol GetAliasInfo( ISemanticFactsService semanticFacts, SemanticModel model, SyntaxToken token, CancellationToken cancellationToken) { if (semanticFacts == null) { return(model.GetAliasInfo(token.Parent, cancellationToken)); } var entry = GetCachedEntry(model); if (entry == null) { return(model.GetAliasInfo(token.Parent, cancellationToken)); } if (entry.AliasNameSet == null) { var set = semanticFacts.GetAliasNameSet(model, cancellationToken); Interlocked.CompareExchange(ref entry.AliasNameSet, set, null); } if (entry.AliasNameSet.Contains(token.ValueText)) { return(model.GetAliasInfo(token.Parent, cancellationToken)); } return(null); }
public static IAliasSymbol GetAliasInfo( ISemanticFactsService semanticFacts, SemanticModel model, SyntaxToken token, CancellationToken cancellationToken) { if (semanticFacts == null) { return model.GetAliasInfo(token.Parent, cancellationToken); } var entry = GetCachedEntry(model); if (entry == null) { return model.GetAliasInfo(token.Parent, cancellationToken); } if (entry.AliasNameSet == null) { var set = semanticFacts.GetAliasNameSet(model, cancellationToken); Interlocked.CompareExchange(ref entry.AliasNameSet, set, null); } if (entry.AliasNameSet.Contains(token.ValueText)) { return model.GetAliasInfo(token.Parent, cancellationToken); } return null; }
/// <summary> /// Determines whether the specified TypeSyntax is actually 'var'. /// </summary> public static bool IsTypeInferred(this TypeSyntax typeSyntax, SemanticModel semanticModel) { if (!typeSyntax.IsVar) { return(false); } if (semanticModel.GetAliasInfo(typeSyntax) != null) { return(false); } var type = semanticModel.GetTypeInfo(typeSyntax).Type; if (type == null) { return(false); } if (type.Name == "var") { return(false); } return(true); }
public static NameSyntax EnsureFullyQualifiedName( NameSyntax name, SemanticModel semanticModel, CancellationToken cancellationToken = default(CancellationToken)) { ISymbol symbol = semanticModel.GetSymbol(name, cancellationToken); if (symbol != null) { if (semanticModel.GetAliasInfo(name, cancellationToken) != null || !symbol.ContainingNamespace.IsGlobalNamespace) { SymbolKind kind = symbol.Kind; if (kind == SymbolKind.Namespace) { return(SyntaxFactory.ParseName(symbol.ToString()).WithTriviaFrom(name)); } else if (kind == SymbolKind.NamedType) { return((NameSyntax)((INamedTypeSymbol)symbol).ToTypeSyntax(_symbolDisplayFormat).WithTriviaFrom(name)); } } } return(name); }
/// <summary> /// Determines whether the specified TypeSyntax is actually 'var'. /// </summary> public static bool IsTypeInferred(this TypeSyntax typeSyntax, SemanticModel semanticModel) { if (!typeSyntax.IsVar) { return false; } if (semanticModel.GetAliasInfo(typeSyntax) != null) { return false; } var type = semanticModel.GetTypeInfo(typeSyntax).Type; if (type == null) { return false; } if (type.Name == "var") { return false; } return true; }
private static UsingDirectiveSyntax EnsureFullyQualifiedName(UsingDirectiveSyntax usingDirective, SemanticModel semanticModel, CancellationToken cancellationToken) { NameSyntax name = usingDirective.Name; NameSyntax newName = EnsureFullyQualifiedName(); newName = newName.WithTriviaFrom(name); return(usingDirective.WithName(newName).WithFormatterAnnotation()); NameSyntax EnsureFullyQualifiedName() { ISymbol symbol = semanticModel.GetSymbol(name, cancellationToken); if (symbol != null) { if (semanticModel.GetAliasInfo(name, cancellationToken) != null || !symbol.ContainingNamespace.IsGlobalNamespace) { SymbolKind kind = symbol.Kind; if (kind == SymbolKind.Namespace) { return(SyntaxFactory.ParseName(symbol.ToString()).WithTriviaFrom(name)); } else if (kind == SymbolKind.NamedType) { return((NameSyntax)((INamedTypeSymbol)symbol).ToTypeSyntax(_symbolDisplayFormat).WithTriviaFrom(name)); } } } return(name); } }
public static SemanticInfoSummary GetSemanticInfoSummary(this SemanticModel semanticModel, SyntaxNode node) { SemanticInfoSummary summary = new SemanticInfoSummary(); // The information that is available varies by the type of the syntax node. SymbolInfo symbolInfo = SymbolInfo.None; if (node is ExpressionSyntax expr) { symbolInfo = semanticModel.GetSymbolInfo(expr); summary.ConstantValue = semanticModel.GetConstantValue(expr); var typeInfo = semanticModel.GetTypeInfo(expr); summary.Type = (TypeSymbol)typeInfo.Type; summary.ConvertedType = (TypeSymbol)typeInfo.ConvertedType; summary.ImplicitConversion = semanticModel.GetConversion(expr); summary.MemberGroup = semanticModel.GetMemberGroup(expr); } else if (node is AttributeSyntax attribute) { symbolInfo = semanticModel.GetSymbolInfo(attribute); var typeInfo = semanticModel.GetTypeInfo(attribute); summary.Type = (TypeSymbol)typeInfo.Type; summary.ConvertedType = (TypeSymbol)typeInfo.ConvertedType; summary.ImplicitConversion = semanticModel.GetConversion(attribute); summary.MemberGroup = semanticModel.GetMemberGroup(attribute); } else if (node is OrderingSyntax ordering) { symbolInfo = semanticModel.GetSymbolInfo(ordering); } else if (node is SelectOrGroupClauseSyntax selectOrGroupClause) { symbolInfo = semanticModel.GetSymbolInfo(selectOrGroupClause); } else if (node is ConstructorInitializerSyntax initializer) { symbolInfo = semanticModel.GetSymbolInfo(initializer); var typeInfo = semanticModel.GetTypeInfo(initializer); summary.Type = (TypeSymbol)typeInfo.Type; summary.ConvertedType = (TypeSymbol)typeInfo.ConvertedType; summary.ImplicitConversion = semanticModel.GetConversion(initializer); summary.MemberGroup = semanticModel.GetMemberGroup(initializer); } else { throw ExceptionUtilities.UnexpectedValue(node); } summary.Symbol = (Symbol)symbolInfo.Symbol; summary.CandidateReason = symbolInfo.CandidateReason; summary.CandidateSymbols = symbolInfo.CandidateSymbols; if (node is IdentifierNameSyntax identifier) { summary.Alias = semanticModel.GetAliasInfo(identifier); } return(summary); }
private void AliasSymbolDetailsMenuItem_Click(object sender, RoutedEventArgs e) { var currentTag = (SyntaxTag)_currentSelection.Tag; if ((SemanticModel != null) && (currentTag.Category == SyntaxCategory.SyntaxNode)) { var symbol = SemanticModel.GetAliasInfo(currentTag.SyntaxNode); DisplaySymbolInPropertyGrid(symbol); } }
private bool TryClassifySymbol( NameSyntax name, ISymbol symbol, SemanticModel semanticModel, CancellationToken cancellationToken, out ClassifiedSpan classifiedSpan) { if (symbol != null) { // see through using aliases if (symbol.Kind == SymbolKind.Alias) { symbol = (symbol as IAliasSymbol).Target; } else if (symbol.IsConstructor()) { symbol = symbol.ContainingType; } } if (name.IsVar && IsInVarContext(name)) { var alias = semanticModel.GetAliasInfo(name, cancellationToken); if (alias == null || alias.Name != "var") { if (!IsSymbolCalledVar(symbol)) { // We bound to a symbol. If we bound to a symbol called "var" then we want to // classify this appropriately as a type. Otherwise, we want to classify this as // a keyword. classifiedSpan = new ClassifiedSpan(name.Span, ClassificationTypeNames.Keyword); return(true); } } } if (symbol != null) { // Use .Equals since we can't rely on object identity for constructed types. if (symbol is ITypeSymbol) { var classification = GetClassificationForType((ITypeSymbol)symbol); if (classification != null) { var token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, classification); return(true); } } } classifiedSpan = default(ClassifiedSpan); return(false); }
public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) { IAliasSymbol aliasSymbol = SemanticModel.GetAliasInfo(node, CancellationToken); if (SymbolEqualityComparer.Default.Equals(aliasSymbol, AliasSymbol)) { return(Replacement .WithTriviaFrom(node) .WithSimplifierAnnotation()); } return(base.VisitIdentifierName(node)); }
public static async Task <Document> VisitAsync( Document document, UsingDirectiveSyntax usingDirective, CancellationToken cancellationToken = default(CancellationToken)) { if (document == null) { throw new ArgumentNullException(nameof(document)); } if (usingDirective == null) { throw new ArgumentNullException(nameof(usingDirective)); } SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); SyntaxTree tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var aliasSymbol = semanticModel.GetDeclaredSymbol(usingDirective, cancellationToken) as IAliasSymbol; var identifierNames = new List <IdentifierNameSyntax>(); IEnumerable <ReferencedSymbol> referencedSymbols = await SymbolFinder.FindReferencesAsync(aliasSymbol, document.Project.Solution, cancellationToken).ConfigureAwait(false); foreach (TextSpan span in GetSymbolSpans(referencedSymbols, tree)) { IdentifierNameSyntax identifierName = root .FindNode(span, getInnermostNodeForTie: true) .FirstAncestorOrSelf <IdentifierNameSyntax>(); if (identifierName != null && aliasSymbol == semanticModel.GetAliasInfo(identifierName, cancellationToken)) { identifierNames.Add(identifierName); } } var rewriter = new InlineAliasExpressionSyntaxRewriter(usingDirective, identifierNames.ToArray()); SyntaxNode newRoot = rewriter.Visit(root); usingDirective = (UsingDirectiveSyntax)newRoot.FindNode(usingDirective.Span); newRoot = newRoot.RemoveNode(usingDirective, GetRemoveOptions(usingDirective)); return(document.WithSyntaxRoot(newRoot)); }
private static bool TryClassifySymbol( NameSyntax name, [NotNullWhen(returnValue: true)] ISymbol?symbol, SemanticModel semanticModel, CancellationToken cancellationToken, out ClassifiedSpan classifiedSpan) { // For Namespace parts, we want don't want to classify the QualifiedNameSyntax // nodes, we instead wait for the each IdentifierNameSyntax node to avoid // creating overlapping ClassifiedSpans. if (symbol is INamespaceSymbol namespaceSymbol && name is IdentifierNameSyntax identifierNameSyntax) { // Do not classify the global:: namespace. It is already syntactically classified as a keyword. var isGlobalNamespace = namespaceSymbol.IsGlobalNamespace && identifierNameSyntax.Identifier.IsKind(SyntaxKind.GlobalKeyword); if (isGlobalNamespace) { classifiedSpan = default; return(false); } // Classifies both extern aliases and namespaces. classifiedSpan = new ClassifiedSpan(name.Span, ClassificationTypeNames.NamespaceName); return(true); } if (name.IsVar && IsInVarContext(name)) { var alias = semanticModel.GetAliasInfo(name, cancellationToken); if (alias == null || alias.Name != "var") { if (!IsSymbolWithName(symbol, "var")) { // We bound to a symbol. If we bound to a symbol called "var" then we want to // classify this appropriately as a type. Otherwise, we want to classify this as // a keyword. classifiedSpan = new ClassifiedSpan(name.Span, ClassificationTypeNames.Keyword); return(true); } } } if (name is IdentifierNameSyntax { Identifier.Text : "args" } &&
private bool TryClassifySymbol( NameSyntax name, ISymbol symbol, SemanticModel semanticModel, CancellationToken cancellationToken, out ClassifiedSpan classifiedSpan) { // Classify a reference to an attribute constructor in an attribute location // as if we were classifying the attribute type itself. if (symbol.IsConstructor() && name.IsParentKind(SyntaxKind.Attribute)) { symbol = symbol.ContainingType; } if (name.IsVar && IsInVarContext(name)) { var alias = semanticModel.GetAliasInfo(name, cancellationToken); if (alias == null || alias.Name != "var") { if (!IsSymbolCalledVar(symbol)) { // We bound to a symbol. If we bound to a symbol called "var" then we want to // classify this appropriately as a type. Otherwise, we want to classify this as // a keyword. classifiedSpan = new ClassifiedSpan(name.Span, ClassificationTypeNames.Keyword); return(true); } } } // Use .Equals since we can't rely on object identity for constructed types. if (symbol is ITypeSymbol typeSymbol) { var classification = GetClassificationForType(typeSymbol); if (classification != null) { var token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, classification); return(true); } } classifiedSpan = default; return(false); }
private static TokenSemanticInfo GetSemanticInfo( SemanticModel semanticModel, ISemanticFactsService semanticFacts, ISyntaxFactsService syntaxFacts, SyntaxToken token, CancellationToken cancellationToken) { var aliasSymbol = semanticModel.GetAliasInfo(token.Parent, cancellationToken); var bindableParent = syntaxFacts.GetBindableParent(token); var type = semanticModel.GetTypeInfo(bindableParent, cancellationToken).Type; var declaredSymbol = MapSymbol(semanticFacts.GetDeclaredSymbol(semanticModel, token, cancellationToken), type); var allSymbols = semanticModel.GetSymbolInfo(bindableParent, cancellationToken) .GetBestOrAllSymbols() .WhereAsArray(s => !s.Equals(declaredSymbol)) .SelectAsArray(s => MapSymbol(s, type)); // NOTE(cyrusn): This is a workaround to how the semantic model binds and returns // information for VB event handlers. Namely, if you have: // // Event X]() // Sub Foo() // Dim y = New $$XEventHandler(AddressOf bar) // End Sub // // Only GetTypeInfo will return any information for XEventHandler. So, in this // case, we upgrade the type to be the symbol we return. if (type != null && allSymbols.Length == 0) { if (type.Kind == SymbolKind.NamedType) { var namedType = (INamedTypeSymbol)type; if (namedType.TypeKind == TypeKind.Delegate || namedType.AssociatedSymbol != null) { allSymbols = ImmutableArray.Create <ISymbol>(type); type = null; } } } return(new TokenSemanticInfo(declaredSymbol, aliasSymbol, allSymbols, type)); }
private ImmutableArray <ISymbol> GetSymbolsByToken( SemanticModel semanticModel, SyntaxToken token, CancellationToken cancellationToken) { // NOTE: try to get overridden symbol when token is `override` keyword if (TryGetIdentifierByOverrideToken(token, out var identifier)) { var overriddenSymbol = semanticModel.GetDeclaredSymbol(identifier, cancellationToken).GetOverriddenSymbol(); return(overriddenSymbol is null ? ImmutableArray <ISymbol> .Empty : ImmutableArray.Create(overriddenSymbol)); } var builder = ImmutableArray.CreateBuilder <ISymbol>(); void AddToBuilder(ISymbol input) { if (!(input is null)) { builder.Add(input); } } var relevantParent = GetRelevantParent(token); var typeInfo = semanticModel.GetTypeInfo(relevantParent, cancellationToken); var type = typeInfo.Type; var convertedType = typeInfo.ConvertedType; var declaredSymbol = semanticModel.GetDeclaredSymbol(token, cancellationToken); var aliasSymbol = semanticModel.GetAliasInfo(relevantParent, cancellationToken); AddToBuilder(declaredSymbol); AddToBuilder(aliasSymbol); // NOTE: and try to get any other symbols (overloads or something else) foreach (var item in semanticModel.GetSymbolOrCandidates(relevantParent, cancellationToken)) { var symbol = GetRelevantSymbol(item); if (symbol is null || symbol.Equals(declaredSymbol)) { continue; } builder.Add(symbol); } AddToBuilder(type); AddToBuilder(convertedType); return(builder.TryMoveToImmutable()); }
private static List <IdentifierNameSyntax> CollectNames( SyntaxNode node, IAliasSymbol aliasSymbol, SemanticModel semanticModel, CancellationToken cancellationToken) { var names = new List <IdentifierNameSyntax>(); foreach (SyntaxNode descendant in node.DescendantNodes()) { if (descendant.Kind() == SyntaxKind.IdentifierName) { IAliasSymbol symbol = semanticModel.GetAliasInfo(descendant, cancellationToken); if (symbol?.Equals(aliasSymbol) == true) { names.Add((IdentifierNameSyntax)descendant); } } } return(names); }
public override bool TrySimplify( NameSyntax name, SemanticModel semanticModel, OptionSet optionSet, out TypeSyntax replacementNode, out TextSpan issueSpan, CancellationToken cancellationToken) { replacementNode = null; issueSpan = default; if (name.IsVar) { return(false); } // we should not simplify a name of a namespace declaration if (IsPartOfNamespaceDeclarationName(name)) { return(false); } // We can simplify Qualified names and AliasQualifiedNames. Generally, if we have // something like "A.B.C.D", we only consider the full thing something we can simplify. // However, in the case of "A.B.C<>.D", then we'll only consider simplifying up to the // first open name. This is because if we remove the open name, we'll often change // meaning as "D" will bind to C<T>.D which is different than C<>.D! if (name is QualifiedNameSyntax qualifiedName) { var left = qualifiedName.Left; if (ContainsOpenName(left)) { // Don't simplify A.B<>.C return(false); } } // 1. see whether binding the name binds to a symbol/type. if not, it is ambiguous and // nothing we can do here. var symbol = SimplificationHelpers.GetOriginalSymbolInfo(semanticModel, name); if (symbol == null) { return(false); } // treat constructor names as types var method = symbol as IMethodSymbol; if (method.IsConstructor()) { symbol = method.ContainingType; } if (symbol.Kind == SymbolKind.Method && name.Kind() == SyntaxKind.GenericName) { var genericName = (GenericNameSyntax)name; replacementNode = SyntaxFactory.IdentifierName(genericName.Identifier) .WithLeadingTrivia(genericName.GetLeadingTrivia()) .WithTrailingTrivia(genericName.GetTrailingTrivia()); issueSpan = genericName.TypeArgumentList.Span; return(CanReplaceWithReducedName( name, replacementNode, semanticModel, cancellationToken)); } if (!(symbol is INamespaceOrTypeSymbol)) { return(false); } if (name.HasAnnotations(SpecialTypeAnnotation.Kind)) { replacementNode = SyntaxFactory.PredefinedType( SyntaxFactory.Token( name.GetLeadingTrivia(), GetPredefinedKeywordKind(SpecialTypeAnnotation.GetSpecialType(name.GetAnnotations(SpecialTypeAnnotation.Kind).First())), name.GetTrailingTrivia())); issueSpan = name.Span; return(CanReplaceWithReducedNameInContext(name, replacementNode, semanticModel)); } else { if (!name.IsRightSideOfDotOrColonColon()) { if (TryReplaceExpressionWithAlias(name, 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(); } var identifierToken = SyntaxFactory.Identifier( name.GetLeadingTrivia(), SyntaxKind.IdentifierToken, text, aliasReplacement.Name, name.GetTrailingTrivia()); identifierToken = CSharpSimplificationService.TryEscapeIdentifierToken(identifierToken, name); replacementNode = SyntaxFactory.IdentifierName(identifierToken); // Merge annotation to new syntax node var annotatedNodesOrTokens = name.GetAnnotatedNodesAndTokens(RenameAnnotation.Kind); foreach (var annotatedNodeOrToken in annotatedNodesOrTokens) { if (annotatedNodeOrToken.IsToken) { identifierToken = annotatedNodeOrToken.AsToken().CopyAnnotationsTo(identifierToken); } else { replacementNode = annotatedNodeOrToken.AsNode().CopyAnnotationsTo(replacementNode); } } annotatedNodesOrTokens = name.GetAnnotatedNodesAndTokens(AliasAnnotation.Kind); foreach (var annotatedNodeOrToken in annotatedNodesOrTokens) { if (annotatedNodeOrToken.IsToken) { identifierToken = annotatedNodeOrToken.AsToken().CopyAnnotationsTo(identifierToken); } else { replacementNode = annotatedNodeOrToken.AsNode().CopyAnnotationsTo(replacementNode); } } replacementNode = ((SimpleNameSyntax)replacementNode).WithIdentifier(identifierToken); issueSpan = name.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 (name.Kind() == SyntaxKind.QualifiedName) { var qualifiedName3 = (QualifiedNameSyntax)name; if (qualifiedName3.Right.Identifier.ValueText == identifierToken.ValueText) { issueSpan = qualifiedName3.Left.Span; } } // first check if this would be a valid reduction if (CanReplaceWithReducedNameInContext(name, replacementNode, semanticModel)) { // in case this alias name ends with "Attribute", we're going to see if we can also // remove that suffix. if (TryReduceAttributeSuffix( name, identifierToken, out var replacementNodeWithoutAttributeSuffix, out var issueSpanWithoutAttributeSuffix)) { if (CanReplaceWithReducedName(name, replacementNodeWithoutAttributeSuffix, semanticModel, cancellationToken)) { replacementNode = replacementNode.CopyAnnotationsTo(replacementNodeWithoutAttributeSuffix); issueSpan = issueSpanWithoutAttributeSuffix; } } return(true); } return(false); } var nameHasNoAlias = false; if (name is SimpleNameSyntax simpleName) { if (!simpleName.Identifier.HasAnnotations(AliasAnnotation.Kind)) { nameHasNoAlias = true; } } if (name is QualifiedNameSyntax qualifiedName2) { if (!qualifiedName2.Right.HasAnnotation(Simplifier.SpecialTypeAnnotation)) { nameHasNoAlias = true; } } if (name is AliasQualifiedNameSyntax aliasQualifiedName) { if (aliasQualifiedName.Name is SimpleNameSyntax && !aliasQualifiedName.Name.Identifier.HasAnnotations(AliasAnnotation.Kind) && !aliasQualifiedName.Name.HasAnnotation(Simplifier.SpecialTypeAnnotation)) { nameHasNoAlias = true; } } var aliasInfo = semanticModel.GetAliasInfo(name, cancellationToken); if (nameHasNoAlias && aliasInfo == null) { // Don't simplify to predefined type if name is part of a QualifiedName. // QualifiedNames can't contain PredefinedTypeNames (although MemberAccessExpressions can). // In other words, the left side of a QualifiedName can't be a PredefinedTypeName. var inDeclarationContext = PreferPredefinedTypeKeywordInDeclarations(name, optionSet, semanticModel); var inMemberAccessContext = PreferPredefinedTypeKeywordInMemberAccess(name, optionSet, semanticModel); if (!name.Parent.IsKind(SyntaxKind.QualifiedName) && (inDeclarationContext || inMemberAccessContext)) { // See if we can simplify this name (like System.Int32) to a built-in type (like 'int'). // If not, we'll still fall through and see if we can convert it to Int32. var codeStyleOptionName = inDeclarationContext ? nameof(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInDeclaration) : nameof(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess); var type = semanticModel.GetTypeInfo(name, cancellationToken).Type; if (type != null) { var keywordKind = GetPredefinedKeywordKind(type.SpecialType); if (keywordKind != SyntaxKind.None && CanReplaceWithPredefinedTypeKeywordInContext(name, semanticModel, out replacementNode, ref issueSpan, keywordKind, codeStyleOptionName)) { return(true); } } else { var typeSymbol = semanticModel.GetSymbolInfo(name, cancellationToken).Symbol; if (typeSymbol.IsKind(SymbolKind.NamedType)) { var keywordKind = GetPredefinedKeywordKind(((INamedTypeSymbol)typeSymbol).SpecialType); if (keywordKind != SyntaxKind.None && CanReplaceWithPredefinedTypeKeywordInContext(name, semanticModel, out replacementNode, ref issueSpan, keywordKind, codeStyleOptionName)) { return(true); } } } } } // Nullable rewrite: Nullable<int> -> int? // Don't rewrite in the case where Nullable<int> is part of some qualified name like Nullable<int>.Something if (!name.IsVar && symbol.Kind == SymbolKind.NamedType && !name.IsLeftSideOfQualifiedName()) { var type = (INamedTypeSymbol)symbol; if (aliasInfo == null && CanSimplifyNullable(type, name, semanticModel)) { GenericNameSyntax genericName; if (name.Kind() == SyntaxKind.QualifiedName) { genericName = (GenericNameSyntax)((QualifiedNameSyntax)name).Right; } else { genericName = (GenericNameSyntax)name; } var oldType = genericName.TypeArgumentList.Arguments.First(); if (oldType.Kind() == SyntaxKind.OmittedTypeArgument) { return(false); } replacementNode = SyntaxFactory.NullableType(oldType) .WithLeadingTrivia(name.GetLeadingTrivia()) .WithTrailingTrivia(name.GetTrailingTrivia()); issueSpan = name.Span; // we need to simplify the whole qualified name at once, because replacing the identifier on the left in // System.Nullable<int> alone would be illegal. // If this fails we want to continue to try at least to remove the System if possible. if (CanReplaceWithReducedNameInContext(name, replacementNode, semanticModel)) { return(true); } } } } SyntaxToken identifier; switch (name.Kind()) { case SyntaxKind.AliasQualifiedName: var simpleName = ((AliasQualifiedNameSyntax)name).Name .WithLeadingTrivia(name.GetLeadingTrivia()); simpleName = simpleName.ReplaceToken(simpleName.Identifier, ((AliasQualifiedNameSyntax)name).Name.Identifier.CopyAnnotationsTo( simpleName.Identifier.WithLeadingTrivia( ((AliasQualifiedNameSyntax)name).Alias.Identifier.LeadingTrivia))); replacementNode = simpleName; issueSpan = ((AliasQualifiedNameSyntax)name).Alias.Span; break; case SyntaxKind.QualifiedName: replacementNode = ((QualifiedNameSyntax)name).Right.WithLeadingTrivia(name.GetLeadingTrivia()); issueSpan = ((QualifiedNameSyntax)name).Left.Span; break; case SyntaxKind.IdentifierName: identifier = ((IdentifierNameSyntax)name).Identifier; // we can try to remove the Attribute suffix if this is the attribute name TryReduceAttributeSuffix(name, identifier, out replacementNode, out issueSpan); break; } } if (replacementNode == null) { return(false); } // We may be looking at a name `X.Y` seeing if we can replace it with `Y`. However, in // order to know for sure, we actually have to look slightly higher at `X.Y.Z` to see if // it can simplify to `Y.Z`. This is because in the `Color Color` case we can only tell // if we can reduce by looking by also looking at what comes next to see if it will // cause the simplified name to bind to the instance or static side. if (TryReduceCrefColorColor(name, replacementNode, semanticModel, cancellationToken)) { return(true); } return(CanReplaceWithReducedName(name, replacementNode, semanticModel, cancellationToken)); }
private static async Task <Document> MakeConstAsync(Document document, LocalDeclarationStatementSyntax localDeclaration, CancellationToken cancellationToken) { // Remove the leading trivia from the local declaration. SyntaxToken firstToken = localDeclaration.GetFirstToken(); SyntaxTriviaList leadingTrivia = firstToken.LeadingTrivia; LocalDeclarationStatementSyntax trimmedLocal = localDeclaration.ReplaceToken( firstToken, firstToken.WithLeadingTrivia(SyntaxTriviaList.Empty)); // Create a const token with the leading trivia. SyntaxToken constToken = SyntaxFactory.Token(leadingTrivia, SyntaxKind.ConstKeyword, SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker)); // Insert the const token into the modifiers list, creating a new modifiers list. SyntaxTokenList newModifiers = trimmedLocal.Modifiers.Insert(0, constToken); // If the type of declaration is 'var', create a new type name for the // type inferred for 'var'. VariableDeclarationSyntax variableDeclaration = localDeclaration.Declaration; TypeSyntax variableTypeName = variableDeclaration.Type; if (variableTypeName.IsVar) { SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); // Special case: Ensure that 'var' isn't actually an alias to another type // (e.g. using var = System.String). IAliasSymbol aliasInfo = semanticModel.GetAliasInfo(variableTypeName, cancellationToken); if (aliasInfo == null) { // Retrieve the type inferred for var. ITypeSymbol type = semanticModel.GetTypeInfo(variableTypeName, cancellationToken).ConvertedType; // Special case: Ensure that 'var' isn't actually a type named 'var'. if (type.Name != "var") { // Create a new TypeSyntax for the inferred type. Be careful // to keep any leading and trailing trivia from the var keyword. TypeSyntax typeName = SyntaxFactory.ParseTypeName(type.ToDisplayString()) .WithLeadingTrivia(variableTypeName.GetLeadingTrivia()) .WithTrailingTrivia(variableTypeName.GetTrailingTrivia()); // Add an annotation to simplify the type name. TypeSyntax simplifiedTypeName = typeName.WithAdditionalAnnotations(Simplifier.Annotation); // Replace the type in the variable declaration. variableDeclaration = variableDeclaration.WithType(simplifiedTypeName); } } } // Produce the new local declaration. LocalDeclarationStatementSyntax newLocal = trimmedLocal.WithModifiers(newModifiers) .WithDeclaration(variableDeclaration); // Add an annotation to format the new local declaration. LocalDeclarationStatementSyntax formattedLocal = newLocal.WithAdditionalAnnotations(Formatter.Annotation); // Replace the old local declaration with the new local declaration. SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); SyntaxNode newRoot = root.ReplaceNode(localDeclaration, formattedLocal); // Return document with transformed tree. return(document.WithSyntaxRoot(newRoot)); }
private bool TryClassifySymbol( NameSyntax name, ISymbol symbol, SemanticModel semanticModel, CancellationToken cancellationToken, out ClassifiedSpan classifiedSpan) { if (symbol != null) { // see through using aliases if (symbol.Kind == SymbolKind.Alias) { symbol = (symbol as IAliasSymbol).Target; } else if (symbol.IsConstructor() && name.IsParentKind(SyntaxKind.Attribute)) { symbol = symbol.ContainingType; } } if (name.IsVar && IsInVarContext(name)) { var alias = semanticModel.GetAliasInfo(name, cancellationToken); if (alias == null || alias.Name != "var") { if (!IsSymbolCalledVar(symbol)) { // We bound to a symbol. If we bound to a symbol called "var" then we want to // classify this appropriately as a type. Otherwise, we want to classify this as // a keyword. classifiedSpan = new ClassifiedSpan(name.Span, ClassificationTypeNames.Keyword); return true; } } } if (symbol != null) { // Use .Equals since we can't rely on object identity for constructed types. if (symbol is ITypeSymbol) { var classification = GetClassificationForType((ITypeSymbol)symbol); if (classification != null) { var token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, classification); return true; } } } classifiedSpan = default(ClassifiedSpan); return false; }
/// <summary> /// Checks if the Name part of the given using directive starts with an alias. /// </summary> /// <param name="usingDirective">The <see cref="UsingDirectiveSyntax"/> that will be used.</param> /// <param name="semanticModel">The <see cref="SemanticModel"/> that will be used.</param> /// <param name="cancellationToken">The cancellation token that can be used to interrupt the operation.</param> /// <returns>True if the name part of the using directive starts with an alias.</returns> internal static bool StartsWithAlias(this UsingDirectiveSyntax usingDirective, SemanticModel semanticModel, CancellationToken cancellationToken) { var firstPart = usingDirective.Name.DescendantNodes().FirstOrDefault() ?? usingDirective.Name; return(semanticModel.GetAliasInfo(firstPart, cancellationToken) != null); }
private static bool TryReplaceWithAlias(this ExpressionSyntax node, SemanticModel semanticModel, bool preferAliasToQualifiedName, CancellationToken cancellationToken, out IAliasSymbol aliasReplacement) { aliasReplacement = null; if (!node.IsAliasReplaceableExpression()) { return false; } var symbol = semanticModel.GetSymbolInfo(node, cancellationToken).Symbol; // If the Symbol is a constructor get its containing type if (symbol.IsConstructor()) { symbol = symbol.ContainingType; } if (node is QualifiedNameSyntax || node is AliasQualifiedNameSyntax) { SyntaxAnnotation aliasAnnotationInfo = null; // The following condition checks if the user has used alias in the original code and // if so the expression is replaced with the Alias if (node is QualifiedNameSyntax) { var qualifiedNameNode = (QualifiedNameSyntax)node; if (qualifiedNameNode.Right.Identifier.HasAnnotations(AliasAnnotation.Kind)) { aliasAnnotationInfo = qualifiedNameNode.Right.Identifier.GetAnnotations(AliasAnnotation.Kind).Single(); } } if (node is AliasQualifiedNameSyntax) { var aliasQualifiedNameNode = (AliasQualifiedNameSyntax)node; if (aliasQualifiedNameNode.Name.Identifier.HasAnnotations(AliasAnnotation.Kind)) { aliasAnnotationInfo = aliasQualifiedNameNode.Name.Identifier.GetAnnotations(AliasAnnotation.Kind).Single(); } } if (aliasAnnotationInfo != null) { var aliasName = AliasAnnotation.GetAliasName(aliasAnnotationInfo); var aliasIdentifier = SyntaxFactory.IdentifierName(aliasName); var aliasTypeInfo = semanticModel.GetSpeculativeAliasInfo(node.SpanStart, aliasIdentifier, SpeculativeBindingOption.BindAsTypeOrNamespace); if (aliasTypeInfo != null) { aliasReplacement = aliasTypeInfo; return ValidateAliasForTarget(aliasReplacement, semanticModel, node, symbol); } } } if (node.Kind() == SyntaxKind.IdentifierName && semanticModel.GetAliasInfo((IdentifierNameSyntax)node, cancellationToken) != null) { return false; } // an alias can only replace a type or namespace if (symbol == null || (symbol.Kind != SymbolKind.Namespace && symbol.Kind != SymbolKind.NamedType)) { return false; } if (node is QualifiedNameSyntax) { var qualifiedName = (QualifiedNameSyntax)node; if (!qualifiedName.Right.HasAnnotation(Simplifier.SpecialTypeAnnotation)) { var type = semanticModel.GetTypeInfo(node, cancellationToken).Type; if (type != null) { var keywordKind = GetPredefinedKeywordKind(type.SpecialType); if (keywordKind != SyntaxKind.None) { preferAliasToQualifiedName = false; } } } } if (node is AliasQualifiedNameSyntax) { var aliasQualifiedNameSyntax = (AliasQualifiedNameSyntax)node; if (!aliasQualifiedNameSyntax.Name.HasAnnotation(Simplifier.SpecialTypeAnnotation)) { var type = semanticModel.GetTypeInfo(node, cancellationToken).Type; if (type != null) { var keywordKind = GetPredefinedKeywordKind(type.SpecialType); if (keywordKind != SyntaxKind.None) { preferAliasToQualifiedName = false; } } } } aliasReplacement = GetAliasForSymbol((INamespaceOrTypeSymbol)symbol, node.GetFirstToken(), semanticModel, cancellationToken); if (aliasReplacement != null && preferAliasToQualifiedName) { return ValidateAliasForTarget(aliasReplacement, semanticModel, node, symbol); } return false; }
private static IEnumerable <ISymbol> GetSymbolsEnumerable( SemanticModel semanticModel, ISemanticFactsService semanticFacts, ISyntaxFactsService syntaxFacts, SyntaxToken token, bool bindLiteralsToUnderlyingType, CancellationToken cancellationToken) { var declaredSymbol = semanticFacts.GetDeclaredSymbol(semanticModel, token, cancellationToken); if (declaredSymbol != null) { yield return(declaredSymbol); yield break; } var aliasInfo = semanticModel.GetAliasInfo(token.Parent, cancellationToken); if (aliasInfo != null) { yield return(aliasInfo); } var bindableParent = syntaxFacts.GetBindableParent(token); var allSymbols = semanticModel.GetSymbolInfo(bindableParent, cancellationToken).GetBestOrAllSymbols().ToList(); var type = semanticModel.GetTypeInfo(bindableParent, cancellationToken).Type; if (type != null && allSymbols.Count == 0) { if ((bindLiteralsToUnderlyingType && syntaxFacts.IsLiteral(token)) || syntaxFacts.IsAwaitKeyword(token)) { yield return(type); } if (type.Kind == SymbolKind.NamedType) { var namedType = (INamedTypeSymbol)type; if (namedType.TypeKind == TypeKind.Delegate || namedType.AssociatedSymbol != null) { yield return(type); } } } foreach (var symbol in allSymbols) { if (symbol.IsThisParameter() && type != null) { yield return(type); } else if (symbol.IsFunctionValue()) { var method = symbol.ContainingSymbol as IMethodSymbol; if (method != null) { if (method.AssociatedSymbol != null) { yield return(method.AssociatedSymbol); } else { yield return(method); } } else { yield return(symbol); } } else { yield return(symbol); } } }
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); }
private static bool TryReduce( this NameSyntax name, SemanticModel semanticModel, out TypeSyntax replacementNode, out TextSpan issueSpan, OptionSet optionSet, CancellationToken cancellationToken) { replacementNode = null; issueSpan = default(TextSpan); if (name.IsVar) { return false; } // we should not simplify a name of a namespace declaration if (IsPartOfNamespaceDeclarationName(name)) { return false; } // We can simplify Qualified names and AliasQualifiedNames. Generally, if we have // something like "A.B.C.D", we only consider the full thing something we can simplify. // However, in the case of "A.B.C<>.D", then we'll only consider simplifying up to the // first open name. This is because if we remove the open name, we'll often change // meaning as "D" will bind to C<T>.D which is different than C<>.D! if (name is QualifiedNameSyntax) { var left = ((QualifiedNameSyntax)name).Left; if (ContainsOpenName(left)) { // Don't simplify A.B<>.C return false; } } // 1. see whether binding the name binds to a symbol/type. if not, it is ambiguous and // nothing we can do here. var symbol = SimplificationHelpers.GetOriginalSymbolInfo(semanticModel, name); if (symbol == null) { return false; } // treat constructor names as types var method = symbol as IMethodSymbol; if (method.IsConstructor()) { symbol = method.ContainingType; } if (symbol.Kind == SymbolKind.Method && name.Kind() == SyntaxKind.GenericName) { // The option wants the generic method invocation name to be explicit, then quit the reduction if (!optionSet.GetOption(SimplificationOptions.PreferImplicitTypeInference)) { return false; } var genericName = (GenericNameSyntax)name; replacementNode = SyntaxFactory.IdentifierName(genericName.Identifier) .WithLeadingTrivia(genericName.GetLeadingTrivia()) .WithTrailingTrivia(genericName.GetTrailingTrivia()); issueSpan = genericName.TypeArgumentList.Span; return name.CanReplaceWithReducedName(replacementNode, semanticModel, cancellationToken); } if (!(symbol is INamespaceOrTypeSymbol)) { return false; } if (name.HasAnnotations(SpecialTypeAnnotation.Kind)) { replacementNode = SyntaxFactory.PredefinedType( SyntaxFactory.Token( name.GetLeadingTrivia(), GetPredefinedKeywordKind(SpecialTypeAnnotation.GetSpecialType(name.GetAnnotations(SpecialTypeAnnotation.Kind).First())), name.GetTrailingTrivia())); issueSpan = name.Span; return name.CanReplaceWithReducedNameInContext(replacementNode, semanticModel, cancellationToken); } else { if (!name.IsRightSideOfDotOrColonColon()) { IAliasSymbol aliasReplacement; if (name.TryReplaceWithAlias(semanticModel, optionSet.GetOption(SimplificationOptions.PreferAliasToQualification), cancellationToken, out 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(); } var identifierToken = SyntaxFactory.Identifier( name.GetLeadingTrivia(), SyntaxKind.IdentifierToken, text, aliasReplacement.Name, name.GetTrailingTrivia()); identifierToken = CSharpSimplificationService.TryEscapeIdentifierToken(identifierToken, name, semanticModel); replacementNode = SyntaxFactory.IdentifierName(identifierToken); // Merge annotation to new syntax node var annotatedNodesOrTokens = name.GetAnnotatedNodesAndTokens(RenameAnnotation.Kind); foreach (var annotatedNodeOrToken in annotatedNodesOrTokens) { if (annotatedNodeOrToken.IsToken) { identifierToken = annotatedNodeOrToken.AsToken().CopyAnnotationsTo(identifierToken); } else { replacementNode = annotatedNodeOrToken.AsNode().CopyAnnotationsTo(replacementNode); } } annotatedNodesOrTokens = name.GetAnnotatedNodesAndTokens(AliasAnnotation.Kind); foreach (var annotatedNodeOrToken in annotatedNodesOrTokens) { if (annotatedNodeOrToken.IsToken) { identifierToken = annotatedNodeOrToken.AsToken().CopyAnnotationsTo(identifierToken); } else { replacementNode = annotatedNodeOrToken.AsNode().CopyAnnotationsTo(replacementNode); } } replacementNode = ((SimpleNameSyntax)replacementNode).WithIdentifier(identifierToken); issueSpan = name.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 (name.Kind() == SyntaxKind.QualifiedName) { QualifiedNameSyntax qualifiedName = (QualifiedNameSyntax)name; if (qualifiedName.Right.Identifier.ValueText == identifierToken.ValueText) { issueSpan = qualifiedName.Left.Span; } } // first check if this would be a valid reduction if (name.CanReplaceWithReducedNameInContext(replacementNode, semanticModel, cancellationToken)) { // in case this alias name ends with "Attribute", we're going to see if we can also // remove that suffix. TypeSyntax replacementNodeWithoutAttributeSuffix; TextSpan issueSpanWithoutAttributeSuffix; if (TryReduceAttributeSuffix( name, identifierToken, semanticModel, out replacementNodeWithoutAttributeSuffix, out issueSpanWithoutAttributeSuffix, cancellationToken)) { if (name.CanReplaceWithReducedName(replacementNodeWithoutAttributeSuffix, semanticModel, cancellationToken)) { replacementNode = replacementNode.CopyAnnotationsTo(replacementNodeWithoutAttributeSuffix); issueSpan = issueSpanWithoutAttributeSuffix; } } return true; } return false; } var nameHasNoAlias = false; if (name is SimpleNameSyntax) { var simpleName = (SimpleNameSyntax)name; if (!simpleName.Identifier.HasAnnotations(AliasAnnotation.Kind)) { nameHasNoAlias = true; } } if (name is QualifiedNameSyntax) { var qualifiedName = (QualifiedNameSyntax)name; if (!qualifiedName.Right.HasAnnotation(Simplifier.SpecialTypeAnnotation)) { nameHasNoAlias = true; } } if (name is AliasQualifiedNameSyntax) { var aliasQualifiedName = (AliasQualifiedNameSyntax)name; if (aliasQualifiedName.Name is SimpleNameSyntax && !aliasQualifiedName.Name.Identifier.HasAnnotations(AliasAnnotation.Kind) && !aliasQualifiedName.Name.HasAnnotation(Simplifier.SpecialTypeAnnotation)) { nameHasNoAlias = true; } } var aliasInfo = semanticModel.GetAliasInfo(name, cancellationToken); if (nameHasNoAlias && aliasInfo == null) { if (IsReplaceableByVar(name, semanticModel, out replacementNode, out issueSpan, optionSet, cancellationToken)) { return true; } // Don't simplify to predefined type if name is part of a QualifiedName. // QualifiedNames can't contain PredefinedTypeNames (although MemberAccessExpressions can). // In other words, the left side of a QualifiedName can't be a PredefinedTypeName. if (!name.Parent.IsKind(SyntaxKind.QualifiedName) && (PreferPredefinedTypeKeywordInDeclarations(name, optionSet, semanticModel) || PreferPredefinedTypeKeywordInMemberAccess(name, optionSet, semanticModel))) { var type = semanticModel.GetTypeInfo(name, cancellationToken).Type; if (type != null) { var keywordKind = GetPredefinedKeywordKind(type.SpecialType); if (keywordKind != SyntaxKind.None) { return CanReplaceWithPredefinedTypeKeywordInContext(name, semanticModel, out replacementNode, ref issueSpan, keywordKind, cancellationToken); } } else { var typeSymbol = semanticModel.GetSymbolInfo(name, cancellationToken).Symbol; if (typeSymbol.IsKind(SymbolKind.NamedType)) { var keywordKind = GetPredefinedKeywordKind(((INamedTypeSymbol)typeSymbol).SpecialType); if (keywordKind != SyntaxKind.None) { return CanReplaceWithPredefinedTypeKeywordInContext(name, semanticModel, out replacementNode, ref issueSpan, keywordKind, cancellationToken); } } } } } // nullable rewrite: Nullable<int> -> int? // Don't rewrite in the case where Nullable<int> is part of some qualified name like Nullable<int>.Something if (!name.IsVar && (symbol.Kind == SymbolKind.NamedType) && !name.IsLeftSideOfQualifiedName()) { var type = (INamedTypeSymbol)symbol; if (aliasInfo == null && CanSimplifyNullable(type, name, semanticModel)) { GenericNameSyntax genericName; if (name.Kind() == SyntaxKind.QualifiedName) { genericName = (GenericNameSyntax)((QualifiedNameSyntax)name).Right; } else { genericName = (GenericNameSyntax)name; } var oldType = genericName.TypeArgumentList.Arguments.First(); if (oldType.Kind() == SyntaxKind.OmittedTypeArgument) { return false; } replacementNode = SyntaxFactory.NullableType(oldType) .WithLeadingTrivia(name.GetLeadingTrivia()) .WithTrailingTrivia(name.GetTrailingTrivia()); issueSpan = name.Span; // we need to simplify the whole qualified name at once, because replacing the identifier on the left in // System.Nullable<int> alone would be illegal. // If this fails we want to continue to try at least to remove the System if possible. if (name.CanReplaceWithReducedNameInContext(replacementNode, semanticModel, cancellationToken)) { return true; } } } } SyntaxToken identifier; switch (name.Kind()) { case SyntaxKind.AliasQualifiedName: var simpleName = ((AliasQualifiedNameSyntax)name).Name .WithLeadingTrivia(name.GetLeadingTrivia()); simpleName = simpleName.ReplaceToken(simpleName.Identifier, ((AliasQualifiedNameSyntax)name).Name.Identifier.CopyAnnotationsTo( simpleName.Identifier.WithLeadingTrivia( ((AliasQualifiedNameSyntax)name).Alias.Identifier.LeadingTrivia))); replacementNode = simpleName; issueSpan = ((AliasQualifiedNameSyntax)name).Alias.Span; break; case SyntaxKind.QualifiedName: replacementNode = ((QualifiedNameSyntax)name).Right.WithLeadingTrivia(name.GetLeadingTrivia()); issueSpan = ((QualifiedNameSyntax)name).Left.Span; break; case SyntaxKind.IdentifierName: identifier = ((IdentifierNameSyntax)name).Identifier; // we can try to remove the Attribute suffix if this is the attribute name TryReduceAttributeSuffix(name, identifier, semanticModel, out replacementNode, out issueSpan, cancellationToken); break; } } if (replacementNode == null) { return false; } return name.CanReplaceWithReducedName(replacementNode, semanticModel, cancellationToken); }
private bool TryClassifySymbol( NameSyntax name, ISymbol symbol, SemanticModel semanticModel, CancellationToken cancellationToken, out ClassifiedSpan classifiedSpan) { // Classify a reference to an attribute constructor in an attribute location // as if we were classifying the attribute type itself. if (symbol.IsConstructor() && name.IsParentKind(SyntaxKind.Attribute)) { symbol = symbol.ContainingType; } if (name.IsVar && IsInVarContext(name)) { var alias = semanticModel.GetAliasInfo(name, cancellationToken); if (alias == null || alias.Name != "var") { if (!IsSymbolCalledVar(symbol)) { // We bound to a symbol. If we bound to a symbol called "var" then we want to // classify this appropriately as a type. Otherwise, we want to classify this as // a keyword. classifiedSpan = new ClassifiedSpan(name.Span, ClassificationTypeNames.Keyword); return(true); } } } // Use .Equals since we can't rely on object identity for constructed types. SyntaxToken token; switch (symbol) { case ITypeSymbol typeSymbol: var classification = GetClassificationForType(typeSymbol); if (classification != null) { token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, classification); return(true); } break; case IFieldSymbol fieldSymbol: token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, GetClassificationForField(fieldSymbol)); return(true); case IMethodSymbol methodSymbol: token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, methodSymbol.IsExtensionMethod ? ClassificationTypeNames.ExtensionMethodName : ClassificationTypeNames.MethodName); return(true); case IPropertySymbol propertySymbol: token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, ClassificationTypeNames.PropertyName); return(true); case IEventSymbol eventSymbol: token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, ClassificationTypeNames.EventName); return(true); case IParameterSymbol parameterSymbol: if (parameterSymbol.IsImplicitlyDeclared && parameterSymbol.Name == "value") { break; } token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, ClassificationTypeNames.ParameterName); return(true); case ILocalSymbol localSymbol: token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, localSymbol.IsConst ? ClassificationTypeNames.ConstantName : ClassificationTypeNames.LocalName); return(true); } classifiedSpan = default; return(false); }
private bool TryClassifySymbol( NameSyntax name, ISymbol symbol, SemanticModel semanticModel, CancellationToken cancellationToken, out ClassifiedSpan classifiedSpan) { // For Namespace parts, we want don't want to classify the QualifiedNameSyntax // nodes, we instead wait for the each IdentifierNameSyntax node to avoid // creating overlapping ClassifiedSpans. if (symbol is INamespaceSymbol namespaceSymbol && name is IdentifierNameSyntax identifierNameSyntax) { // Do not classify the global:: namespace. It is already syntactically classified as a keyword. var isGlobalNamespace = namespaceSymbol.IsGlobalNamespace && identifierNameSyntax.Identifier.IsKind(SyntaxKind.GlobalKeyword); if (isGlobalNamespace) { classifiedSpan = default; return(false); } // Classifies both extern aliases and namespaces. classifiedSpan = new ClassifiedSpan(name.Span, ClassificationTypeNames.NamespaceName); return(true); } if (name.IsNullWithNoType() && IsInVarContext(name)) { var alias = semanticModel.GetAliasInfo(name, cancellationToken); if (alias == null || alias.Name != "var") { if (!IsSymbolWithName(symbol, "var")) { // We bound to a symbol. If we bound to a symbol called "var" then we want to // classify this appropriately as a type. Otherwise, we want to classify this as // a keyword. classifiedSpan = new ClassifiedSpan(name.Span, ClassificationTypeNames.Keyword); return(true); } } } if (name.IsUnmanaged && name.Parent.IsKind(SyntaxKind.ImplementsTypeConstraint)) { var alias = semanticModel.GetAliasInfo(name, cancellationToken); if (alias == null || alias.Name != "unmanaged") { if (!IsSymbolWithName(symbol, "unmanaged")) { // We bound to a symbol. If we bound to a symbol called "unmanaged" then we want to // classify this appropriately as a type. Otherwise, we want to classify this as // a keyword. classifiedSpan = new ClassifiedSpan(name.Span, ClassificationTypeNames.Keyword); return(true); } } } // Use .Equals since we can't rely on object identity for constructed types. SyntaxToken token; switch (symbol) { case ITypeSymbol typeSymbol: var classification = GetClassificationForType(typeSymbol); if (classification != null) { token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, classification); return(true); } break; case IFieldSymbol fieldSymbol: token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, GetClassificationForField(fieldSymbol)); return(true); case IMethodSymbol methodSymbol: token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, GetClassificationForMethod(methodSymbol)); return(true); case IPropertySymbol propertySymbol: token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, ClassificationTypeNames.PropertyName); return(true); case IEventSymbol eventSymbol: token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, ClassificationTypeNames.EventName); return(true); case IParameterSymbol parameterSymbol: if (parameterSymbol.IsImplicitlyDeclared && parameterSymbol.Name == "value") { break; } token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, ClassificationTypeNames.ParameterName); return(true); case ILocalSymbol localSymbol: token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, GetClassificationForLocal(localSymbol)); return(true); case ILabelSymbol labelSymbol: token = name.GetNameToken(); classifiedSpan = new ClassifiedSpan(token.Span, ClassificationTypeNames.LabelName); return(true); } classifiedSpan = default; return(false); }
private IAliasSymbol GetAliasSymbol(SyntaxNode syntaxNode) { SemanticModel semanticModel = GetSemanticModel(); return(semanticModel != null?semanticModel.GetAliasInfo(syntaxNode) : null); }