internal static FieldDeclarationSyntax AddBackingField(this DocumentEditor editor, PropertyDeclarationSyntax propertyDeclaration, bool usesUnderscoreNames, CancellationToken cancellationToken) { var property = editor.SemanticModel.GetDeclaredSymbolSafe(propertyDeclaration, cancellationToken); var name = usesUnderscoreNames ? $"_{property.Name.ToFirstCharLower()}" : property.Name.ToFirstCharLower(); while (property.ContainingType.MemberNames.Any(x => x == name)) { name += "_"; } if (SyntaxFacts.GetKeywordKind(name) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(name) != SyntaxKind.None) { name = "@" + name; } var backingField = (FieldDeclarationSyntax)editor.Generator.FieldDeclaration( name, accessibility: Accessibility.Private, modifiers: DeclarationModifiers.None, type: propertyDeclaration.Type, initializer: propertyDeclaration.Initializer?.Value); var type = (TypeDeclarationSyntax)propertyDeclaration.Parent; editor.ReplaceNode( type, (node, generator) => AddBackingField((TypeDeclarationSyntax)node, backingField, property.Name, generator)); return(backingField); }
/// <summary> /// Create a backing <see cref="FieldDeclarationSyntax"/> for the <paramref name="propertyDeclaration"/> /// Handles name collisions and reserved keywords. /// </summary> /// <param name="editor">The <see cref="DocumentEditor"/>.</param> /// <param name="propertyDeclaration">The <see cref="PropertyDeclarationSyntax"/>.</param> /// <returns>A <see cref="FieldDeclarationSyntax"/>.</returns> public static FieldDeclarationSyntax CreateBackingField(this DocumentEditor editor, PropertyDeclarationSyntax propertyDeclaration) { if (editor is null) { throw new System.ArgumentNullException(nameof(editor)); } if (propertyDeclaration is null) { throw new System.ArgumentNullException(nameof(propertyDeclaration)); } var property = editor.SemanticModel.GetDeclaredSymbol(propertyDeclaration); var name = editor.SemanticModel.UnderscoreFields() == CodeStyleResult.Yes ? $"_{property.Name.ToFirstCharLower()}" : property.Name.ToFirstCharLower(); while (property.ContainingType.MemberNames.Any(x => x == name)) { name += "_"; } if (SyntaxFacts.GetKeywordKind(name) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(name) != SyntaxKind.None) { name = "@" + name; } return((FieldDeclarationSyntax)editor.Generator.FieldDeclaration( name, accessibility: Accessibility.Private, modifiers: DeclarationModifiers.None, type: propertyDeclaration.Type, initializer: propertyDeclaration.Initializer?.Value)); }
public static bool IsKeyword(this string name) { var isAnyKeyword = SyntaxFacts.GetKeywordKind(name) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(name) != SyntaxKind.None; return(isAnyKeyword); }
protected override Task <ImmutableArray <(ISymbol symbol, bool preselect)> > GetSymbolsAsync( CompletionContext?completionContext, CSharpSyntaxContext context, int position, OptionSet options, CancellationToken cancellationToken ) { var targetToken = context.TargetToken; // Don't want to offer this after "async" (even though the compiler may parse that as a type). if ( SyntaxFacts.GetContextualKeywordKind(targetToken.ValueText) == SyntaxKind.AsyncKeyword ) { return(SpecializedTasks.EmptyImmutableArray <(ISymbol symbol, bool preselect)>()); } var typeNode = targetToken.Parent as TypeSyntax; while (typeNode != null) { if (typeNode.Parent is TypeSyntax parentType && parentType.Span.End < position) { typeNode = parentType; }
public SyntaxKind GetKind() { if (Kind != SyntaxKind.None) { return(Kind); } return(SyntaxFacts.GetAccessorDeclarationKind(SyntaxFacts.GetContextualKeywordKind(KeywordStr))); }
private static void HandleXmlNodeSyntax(SyntaxNodeAnalysisContext context) { var xmlNodeSyntax = (XmlNodeSyntax)context.Node; var name = xmlNodeSyntax.GetName(); if (name is null || name.Prefix != null) { return; } if (name.LocalName.ValueText != XmlCommentHelper.SeeXmlTag) { return; } SyntaxList <XmlAttributeSyntax> attributes; if (xmlNodeSyntax is XmlEmptyElementSyntax xmlEmptyElement) { attributes = xmlEmptyElement.Attributes; } else { attributes = ((XmlElementSyntax)xmlNodeSyntax).StartTag.Attributes; } foreach (var attribute in attributes) { if (attribute.Name is null || attribute.Name.Prefix != null) { continue; } if (attribute.Name.LocalName.ValueText != XmlCommentHelper.LangwordArgumentName) { continue; } var text = ((XmlTextAttributeSyntax)attribute).TextTokens; string valueText; if (text.Count == 1) { valueText = text[0].ValueText; } else { valueText = string.Join(string.Empty, text.Select(textToken => textToken.ValueText)); } if (SyntaxFacts.GetKeywordKind(valueText) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(valueText) != SyntaxKind.None) { continue; } context.ReportDiagnostic(Diagnostic.Create(Descriptor, attribute.Name.LocalName.GetLocation())); } }
private static bool IsKeyWord(string identifier) { if (SyntaxFacts.GetKeywordKind(identifier) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(identifier) != SyntaxKind.None) { return(true); } return(false); }
internal static ClassifiedSpan AdjustStaleClassification(SourceText rawText, ClassifiedSpan classifiedSpan) { // If we marked this as an identifier and it should now be a keyword // (or vice versa), then fix this up and return it. var classificationType = classifiedSpan.ClassificationType; // Check if the token's type has changed. Note: we don't check for "wasPPKeyword && // !isPPKeyword" here. That's because for fault tolerance any identifier will end up // being parsed as a PP keyword eventually, and if we have the check here, the text // flickers between blue and black while typing. See // http://vstfdevdiv:8080/web/wi.aspx?id=3521 for details. var wasKeyword = classificationType == ClassificationTypeNames.Keyword; var wasIdentifier = classificationType == ClassificationTypeNames.Identifier; // We only do this for identifiers/keywords. if (wasKeyword || wasIdentifier) { // Get the current text under the tag. var span = classifiedSpan.TextSpan; var text = rawText.ToString(span); // Now, try to find the token that corresponds to that text. If // we get 0 or 2+ tokens, then we can't do anything with this. // Also, if that text includes trivia, then we can't do anything. var token = SyntaxFactory.ParseToken(text); if (token.Span.Length == span.Length) { // var and dynamic are not contextual keywords. They are always identifiers // (that we classify as keywords). Because we are just parsing a token we don't // know if we're in the right context for them to be identifiers or keywords. // So, we base on decision on what they were before. i.e. if we had a keyword // before, then assume it stays a keyword if we see 'var' or 'dynamic. var isKeyword = SyntaxFacts.IsKeywordKind(token.CSharpKind()) || (wasKeyword && SyntaxFacts.GetContextualKeywordKind(text) != SyntaxKind.None) || (wasKeyword && token.ToString() == "var") || (wasKeyword && token.ToString() == "dynamic"); var isIdentifier = token.CSharpKind() == SyntaxKind.IdentifierToken; // We only do this for identifiers/keywords. if (isKeyword || isIdentifier) { if ((wasKeyword && !isKeyword) || (wasIdentifier && !isIdentifier)) { // It changed! Return the new type of tagspan. return(new ClassifiedSpan( isKeyword ? ClassificationTypeNames.Keyword : ClassificationTypeNames.Identifier, span)); } } } } // didn't need to do anything to this one. return(classifiedSpan); }
public void SyntaxFacts_Keyword_GetContextualKeywordKind_DetectsAllContextualKeywords() { foreach (var kind in SyntaxFacts.GetContextualKeywordKinds()) { var text = kind.GetText(); var keywordKind = SyntaxFacts.GetContextualKeywordKind(text); Assert.Equal(kind, keywordKind); } }
public void SyntaxFacts_Keyword_GetContextualKeywordKind_DetectsAllContextualKeywords_RegardlessOfCase() { foreach (var kind in SyntaxFacts.GetContextualKeywordKinds()) { var text = kind.GetText(); var textWithMixedCast = GetMixedCase(text); var keywordKind = SyntaxFacts.GetContextualKeywordKind(textWithMixedCast); Assert.Equal(kind, keywordKind); } }
public virtual string Identifier([NotNull] string name, [CanBeNull] ICollection <string> scope = null) { Check.NotEmpty(name, nameof(name)); var builder = new StringBuilder(); var partStart = 0; for (var i = 0; i < name.Length; i++) { if (!SyntaxFacts.IsIdentifierPartCharacter(name[i])) { if (partStart != i) { builder.Append(name.Substring(partStart, i - partStart)); } partStart = i + 1; } } if (partStart != name.Length) { builder.Append(name.Substring(partStart)); } if (!SyntaxFacts.IsIdentifierStartCharacter(builder[0])) { builder.Insert(0, "_"); } var identifier = builder.ToString(); if (scope != null) { var uniqueIdentifier = identifier; var qualifier = 0; while (scope.Contains(uniqueIdentifier)) { uniqueIdentifier = identifier + qualifier++; } scope.Add(uniqueIdentifier); identifier = uniqueIdentifier; } if (SyntaxFacts.GetKeywordKind(identifier) != SyntaxKind.None || SyntaxFacts.GetPreprocessorKeywordKind(identifier) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(identifier) != SyntaxKind.None) { return("@" + identifier); } return(identifier); }
public static SyntaxToken TryEscapeIdentifierToken( SyntaxToken syntaxToken, SyntaxNode parentOfToken ) { // do not escape an already escaped identifier if (syntaxToken.IsVerbatimIdentifier()) { return(syntaxToken); } if ( SyntaxFacts.GetKeywordKind(syntaxToken.ValueText) == SyntaxKind.None && SyntaxFacts.GetContextualKeywordKind(syntaxToken.ValueText) == SyntaxKind.None ) { return(syntaxToken); } if ( SyntaxFacts.GetContextualKeywordKind(syntaxToken.ValueText) == SyntaxKind.UnderscoreToken ) { return(syntaxToken); } var parent = parentOfToken.Parent; if (parentOfToken is SimpleNameSyntax && parent.Kind() == SyntaxKind.XmlNameAttribute) { // do not try to escape XML name attributes return(syntaxToken); } // do not escape global in a namespace qualified name if (parent.Kind() == SyntaxKind.AliasQualifiedName && syntaxToken.ValueText == "global") { return(syntaxToken); } // safe to escape identifier return(syntaxToken .CopyAnnotationsTo( SyntaxFactory.VerbatimIdentifier( syntaxToken.LeadingTrivia, syntaxToken.ToString(), syntaxToken.ValueText, syntaxToken.TrailingTrivia ) ) .WithAdditionalAnnotations(Simplifier.Annotation)); }
private static IdentifierNameSyntax CreateIdentifierName(ISymbol candidate) { var identifier = candidate.Name; bool isAnyKeyword = SyntaxFacts.GetKeywordKind(identifier) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(identifier) != SyntaxKind.None; if (isAnyKeyword) { return(SyntaxFactory.IdentifierName("@" + identifier)); } return(SyntaxFactory.IdentifierName(identifier)); }
static SyntaxToken CreateIdentifier(string text) { if (SyntaxFacts.GetKeywordKind(text) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(text) != SyntaxKind.None ) { return (SyntaxFactory.VerbatimIdentifier( SyntaxFactory.TriviaList(), text, text, SyntaxFactory.TriviaList() )); } return(SyntaxFactory.Identifier(text)); }
/// <summary> /// Returns true if this token is something that looks like a C# keyword. This includes /// actual keywords, contextual keywords, and even 'var' and 'dynamic' /// </summary> /// <param name="token"></param> /// <returns></returns> public static bool CouldBeKeyword(this SyntaxToken token) { if (token.IsKeyword()) { return(true); } if (token.Kind() == SyntaxKind.IdentifierToken) { var simpleNameText = token.ValueText; return(simpleNameText == "var" || simpleNameText == "dynamic" || SyntaxFacts.GetContextualKeywordKind(simpleNameText) != SyntaxKind.None); } return(false); }
internal static string Name(this FieldDeclarationSyntax declaration) { VariableDeclaratorSyntax variable = null; if (declaration?.Declaration?.Variables.TrySingle(out variable) == true) { if (SyntaxFacts.GetKeywordKind(variable.Identifier.ValueText) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(variable.Identifier.ValueText) != SyntaxKind.None) { return("@" + variable.Identifier.ValueText); } return(variable.Identifier.ValueText); } throw new InvalidOperationException($"Could not get name of field {declaration}"); }
private static string Name(IPropertySymbol property, SemanticModel semanticModel) { var name = semanticModel.UnderscoreFields() == CodeStyleResult.Yes ? $"_{property.Name.ToFirstCharLower()}" : property.Name.ToFirstCharLower(); while (property.ContainingType.MemberNames.Any(x => x == name)) { name += "_"; } if (SyntaxFacts.GetKeywordKind(name) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(name) != SyntaxKind.None) { name = "@" + name; } return(name); }
public static string SanitiseFieldName(this string name) { name = Regex.Replace(name, @"[\W\b]", "_", RegexOptions.IgnoreCase); name = Regex.Replace(name, @"^\d", @"_$0"); int i = 0; while (SyntaxFacts.GetKeywordKind(name) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(name) != SyntaxKind.None || !SyntaxFacts.IsValidIdentifier(name)) { if (i++ > 10) { return(name); // Sanity check.. The loop might be loopy! } name = "_" + name; } return(name); }
private static bool IsProbablySyntacticConstruct(SyntaxToken token) { // Technically all C# contextual keywords are valid member names. // However some of them start various syntactic constructs // and we don't want to show "Generate <member name>" codefix for them: // 1. "from" starts LINQ expression // 2. "nameof" is probably nameof(some_name) // 3. "async" can start a delegate declaration // 4. "await" starts await expression // 5. "var" is used in constructions like "var x = ..." // The list can be expanded in the future if necessary // This method tells if the given SyntaxToken is one of the cases above var contextualKind = SyntaxFacts.GetContextualKeywordKind(token.ValueText); return(contextualKind is SyntaxKind.FromKeyword or SyntaxKind.NameOfKeyword or SyntaxKind.AsyncKeyword or SyntaxKind.AwaitKeyword or SyntaxKind.VarKeyword); }
private void ReadIdentifierOrKeyword() { var start = _charReader.Position; // Skip first letter NextChar(); // The following characters can be letters, digits the underscore and the dollar sign. while (char.IsLetterOrDigit(_charReader.Current) || _charReader.Current == '_' || _charReader.Current == '$') { NextChar(); } var end = _charReader.Position; var span = TextSpan.FromBounds(start, end); var text = File.Text.GetSubText(span).ToString(); _kind = SyntaxFacts.GetKeywordKind(text); _contextualKind = (_mode == LexerMode.Directive) ? SyntaxFacts.GetPreprocessorKeywordKind(text) : SyntaxFacts.GetContextualKeywordKind(text); switch (_kind) { case SyntaxKind.TrueKeyword: _value = true; break; case SyntaxKind.FalseKeyword: _value = false; break; default: _value = text; break; } }
private void ReadIdentifierOrKeyword() { var start = _charReader.Position; // Skip first letter NextChar(); // The following characters can be letters, digits the underscore and the dollar sign. while (char.IsLetterOrDigit(_charReader.Current) || _charReader.Current == '_' || _charReader.Current == '$') { NextChar(); } var end = _charReader.Position; var span = TextSpan.FromBounds(Text, start, end); var text = Text.GetText(span); _kind = SyntaxFacts.GetUnityKeywordKind(text); _contextualKind = SyntaxFacts.GetContextualKeywordKind(text); switch (_kind) { case SyntaxKind.TrueKeyword: _value = true; break; case SyntaxKind.FalseKeyword: _value = false; break; default: _value = text; break; } }
public override Task ProvideArgumentAsync(ArgumentContext context) { if (context.PreviousValue is not null) { // This argument provider does not attempt to replace arguments already in code. return(Task.CompletedTask); } if (context.Parameter.RefKind != RefKind.Out) { // This argument provider only considers 'out' parameters. return(Task.CompletedTask); } // Since tihs provider runs after ContextVariableArgumentProvider, we know there is no suitable target in // the current context. Instead, offer to declare a new variable. var name = context.Parameter.Name; if (SyntaxFacts.GetKeywordKind(name) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(name) != SyntaxKind.None) { name = "@" + name; } var syntax = SyntaxFactory.Argument( nameColon: null, refKindKeyword: SyntaxFactory.Token(SyntaxKind.OutKeyword), SyntaxFactory.DeclarationExpression( type: SyntaxFactory.IdentifierName("var"), designation: SyntaxFactory.SingleVariableDesignation(SyntaxFactory.Identifier( SyntaxFactory.TriviaList(), contextualKind: SyntaxKind.None, text: name, valueText: context.Parameter.Name, SyntaxFactory.TriviaList())))); context.DefaultValue = syntax.NormalizeWhitespace().ToFullString(); return(Task.CompletedTask); }
/// <summary> /// Create a backing <see cref="FieldDeclarationSyntax"/> for the <paramref name="propertyDeclaration"/> /// Handles name collisions and reserved keywords. /// </summary> /// <param name="editor">The <see cref="DocumentEditor"/>.</param> /// <param name="propertyDeclaration">The <see cref="PropertyDeclarationSyntax"/>.</param> /// <returns>A <see cref="FieldDeclarationSyntax"/>.</returns> public static FieldDeclarationSyntax CreateBackingField(this DocumentEditor editor, PropertyDeclarationSyntax propertyDeclaration) { if (editor is null) { throw new System.ArgumentNullException(nameof(editor)); } if (propertyDeclaration is null) { throw new System.ArgumentNullException(nameof(propertyDeclaration)); } if (propertyDeclaration.Parent is TypeDeclarationSyntax type) { var name = editor.SemanticModel.UnderscoreFields() == CodeStyleResult.Yes ? $"_{propertyDeclaration.Identifier.ValueText.ToFirstCharLower()}" : propertyDeclaration.Identifier.ValueText.ToFirstCharLower(); while (type.TryFindField(name, out _)) { name += "_"; } if (SyntaxFacts.GetKeywordKind(name) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(name) != SyntaxKind.None) { name = "@" + name; } return((FieldDeclarationSyntax)editor.Generator.FieldDeclaration( name, accessibility: Accessibility.Private, modifiers: DeclarationModifiers.None, type: propertyDeclaration.Type, initializer: propertyDeclaration.Initializer?.Value)); } throw new System.ArgumentNullException(nameof(propertyDeclaration), "Property.Parent is not a TypeDeclaration."); }
public static string EscapeIdentifier(this string identifier, bool isQueryContext = false) { var nullIndex = identifier.IndexOf('\0'); if (nullIndex >= 0) { identifier = identifier.Substring(0, nullIndex); } var needsEscaping = SyntaxFacts.GetKeywordKind(identifier) != SyntaxKind.None; // Check if we need to escape this contextual keyword needsEscaping = needsEscaping || ( isQueryContext && SyntaxFacts.IsQueryContextualKeyword( SyntaxFacts.GetContextualKeywordKind(identifier) ) ); return(needsEscaping ? "@" + identifier : identifier); }
private void ReadIdentifierOrKeyword() { var start = _charReader.Position; // Skip first letter _charReader.NextChar(); // The following characters can be letters, digits the underscore and the dollar sign. while (char.IsLetterOrDigit(_charReader.Current) || _charReader.Current == '_' || _charReader.Current == '$') { _charReader.NextChar(); } var end = _charReader.Position; var span = TextSpan.FromBounds(start, end); var text = _text.GetText(span); _kind = SyntaxFacts.GetKeywordKind(text); _contextualKind = SyntaxFacts.GetContextualKeywordKind(text); _value = text; }
protected override int GetKeywordKind(string trimmed) { var kind = SyntaxFacts.GetKeywordKind(trimmed); return((int)(kind == SyntaxKind.None ? SyntaxFacts.GetContextualKeywordKind(trimmed) : kind)); }
public FieldInfoWrapper(IFieldSymbol parameter, MetadataLoadContextInternal metadataLoadContext) { _field = parameter; _metadataLoadContext = metadataLoadContext; NeedsAtSign = SyntaxFacts.GetKeywordKind(_field.Name) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(_field.Name) != SyntaxKind.None; }
private static bool IsPotentialKeyword(string identifier) { return(SyntaxFacts.GetKeywordKind(identifier) != SyntaxKind.None || SyntaxFacts.GetContextualKeywordKind(identifier) != SyntaxKind.None); }
public void SyntaxFacts_Keyword_GetContextualKeywordKind_ReturnsIdentifier_IfNotKeyword() { var keywordKind = SyntaxFacts.GetContextualKeywordKind("ipsum"); Assert.Equal(SyntaxKind.IdentifierToken, keywordKind); }
public void SyntaxFacts_Keyword_GetContextualKeywordKind_ThrowsArgumentNullException_IfTextIsNull() { Assert.Throws <ArgumentNullException>(() => SyntaxFacts.GetContextualKeywordKind(null)); }