private CSharpProperty BuildProperty(IPropertySymbol symbol, CSharpClass referencingClass, string nameSpace = null) { var prop = new CSharpProperty(); var commentXml = symbol.GetDocumentationCommentXml(); var typeName = symbol.Type.Name.ToString(); Dictionary <string, HashSet <string> > references = new Dictionary <string, HashSet <string> >(); var newTypeName = context.GetTsType(symbol.Type, references); //if (newTypeName == null || string.IsNullOrEmpty(newTypeName)) //{ //} // remove the namespace if it's the same if (nameSpace != null && newTypeName.StartsWith(nameSpace)) { newTypeName = newTypeName.Remove(0, nameSpace.Length + 1); // +1 for the dot } if (references.Count > 0) { referencingClass.AddReferences(references); } prop.SetSummaryViaXml(commentXml); var name = symbol.Name.ToString(); prop.DisplayText = name + ": " + newTypeName + ";"; return(prop); }
private void ConfigureBoundAttribute( BoundAttributeDescriptorBuilder builder, IPropertySymbol property, INamedTypeSymbol containingType) { var attributeNameAttribute = property .GetAttributes() .Where(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, _htmlAttributeNameAttributeSymbol)) .FirstOrDefault(); bool hasExplicitName; string attributeName; if (attributeNameAttribute == null || attributeNameAttribute.ConstructorArguments.Length == 0 || string.IsNullOrEmpty((string)attributeNameAttribute.ConstructorArguments[0].Value)) { hasExplicitName = false; attributeName = HtmlConventions.ToHtmlCase(property.Name); } else { hasExplicitName = true; attributeName = (string)attributeNameAttribute.ConstructorArguments[0].Value; } var hasPublicSetter = property.SetMethod != null && property.SetMethod.DeclaredAccessibility == Accessibility.Public; var typeName = GetFullName(property.Type); builder.TypeName = typeName; builder.SetPropertyName(property.Name); if (hasPublicSetter) { builder.Name = attributeName; if (property.Type.TypeKind == TypeKind.Enum) { builder.IsEnum = true; } if (IncludeDocumentation) { var xml = property.GetDocumentationCommentXml(); if (!string.IsNullOrEmpty(xml)) { builder.Documentation = xml; } } } else if (hasExplicitName && !IsPotentialDictionaryProperty(property)) { // Specified HtmlAttributeNameAttribute.Name though property has no public setter. var diagnostic = RazorDiagnosticFactory.CreateTagHelper_InvalidAttributeNameNullOrEmpty(GetFullName(containingType), property.Name); builder.Diagnostics.Add(diagnostic); } ConfigureDictionaryBoundAttribute(builder, property, containingType, attributeNameAttribute, attributeName, hasPublicSetter); }
protected override void ReadSymbol(IPropertySymbol propertySymbol) { // we don't need to know about static members // because they won't be delegated from child to mixin if (propertySymbol.IsStatic) return; // we ignore private and protected memebers var hasGetter = propertySymbol.GetMethod != null && !(propertySymbol.GetMethod.DeclaredAccessibility == Accessibility.Private || propertySymbol.GetMethod.DeclaredAccessibility == Accessibility.Protected); var hasSetter = propertySymbol.SetMethod != null && !(propertySymbol.SetMethod.DeclaredAccessibility == Accessibility.Private || propertySymbol.SetMethod.DeclaredAccessibility == Accessibility.Protected); // property has no accessors or accessors are not accessible => skip property if (!hasSetter && !hasGetter) return; Property property = null; if (propertySymbol.IsIndexer) // symbol is an indexer property { var indexerProperty = new IndexerProperty( propertySymbol.Type, hasGetter, hasSetter); var parameterReader = new ParameterSymbolReader(indexerProperty); parameterReader.VisitSymbol(propertySymbol); property = indexerProperty; } else // symbol is a normal property { property = new Property( propertySymbol.Name, propertySymbol.Type, hasGetter, hasSetter); } property.IsAbstract = propertySymbol.IsAbstract; property.IsOverride = propertySymbol.IsOverride; // store information if accessors are internal, // we will need this for the generation later property.IsGetterInternal = hasGetter && propertySymbol.GetMethod .DeclaredAccessibility.HasFlag(Accessibility.Internal); property.IsSetterInternal = hasSetter && propertySymbol.SetMethod .DeclaredAccessibility.HasFlag(Accessibility.Internal); property.Documentation = new DocumentationComment(propertySymbol.GetDocumentationCommentXml()); _properties.AddProperty(property); }
protected sealed override IEnumerable <Diagnostic> AnalyzeProperty(IPropertySymbol symbol, string commentXml) => AnalyzeComment(symbol, symbol.GetDocumentationCommentXml());
private void CreateProperty(TagHelperDescriptorBuilder builder, IPropertySymbol property, PropertyKind kind) { builder.BindAttribute(pb => { pb.Name = property.Name; pb.TypeName = property.Type.ToDisplayString(FullNameTypeDisplayFormat); pb.SetPropertyName(property.Name); if (kind == PropertyKind.Enum) { pb.IsEnum = true; } if (kind == PropertyKind.ChildContent) { pb.Metadata.Add(BlazorMetadata.Component.ChildContentKey, bool.TrueString); } if (kind == PropertyKind.Delegate) { pb.Metadata.Add(BlazorMetadata.Component.DelegateSignatureKey, bool.TrueString); } if (HasTypeParameter(property.Type)) { pb.Metadata.Add(BlazorMetadata.Component.GenericTypedKey, bool.TrueString); } var xml = property.GetDocumentationCommentXml(); if (!string.IsNullOrEmpty(xml)) { pb.Documentation = xml; } }); bool HasTypeParameter(ITypeSymbol type) { if (type is ITypeParameterSymbol) { return(true); } // We need to check for cases like: // [Parameter] List<T> MyProperty { get; set; } // AND // [Parameter] List<string> MyProperty { get; set; } // // We need to inspect the type arguments to tell the difference between a property that // uses the containing class' type parameter(s) and a vanilla usage of generic types like // List<> and Dictionary<,> // // Since we need to handle cases like RenderFragment<List<T>>, this check must be recursive. if (type is INamedTypeSymbol namedType && namedType.IsGenericType) { var typeArguments = namedType.TypeArguments; for (var i = 0; i < typeArguments.Length; i++) { if (HasTypeParameter(typeArguments[i])) { return(true); } } // Another case to handle - if the type being inspected is a nested type // inside a generic containing class. The common usage for this would be a case // where a generic templated component defines a 'context' nested class. if (namedType.ContainingType != null && HasTypeParameter(namedType.ContainingType)) { return(true); } } return(false); } }
protected override IEnumerable <Diagnostic> AnalyzeProperty(IPropertySymbol symbol) => ShallAnalyzeProperty(symbol) ? AnalyzeProperty(symbol, symbol.GetDocumentationCommentXml()) : Enumerable.Empty <Diagnostic>();
/// <summary> /// Prepares the <see cref="PropertyMemberBuilder"/> from the <paramref name="symbol"/> /// and adds it to <see cref="TypeMemberBuilder.ContentMembers"/> /// </summary> /// <param name="symbol">Source <see cref="INamedTypeSymbol"/></param> /// <param name="root">Builder root</param> /// <param name="type">Parent <see cref="TypeMemberBuilder"/></param> /// <param name="level">Hierarchy level (used to indent the console output)</param> private static void BuildProperty(IPropertySymbol symbol, RootMemberBuilder root, TypeMemberBuilder type, int level) { if (symbol.IsImplicitlyDeclared) { return; } if (symbol.GetAttributes().Any(a => a.AttributeClassString() == "System.Runtime.CompilerServices.CompilerGeneratedAttribute")) { return; } var p = new PropertyMemberBuilder() { Name = symbol.Name, NameBase = symbol.Name.Replace("[]", ""), Symbol = symbol, SourceFiles = symbol.DeclaringSyntaxReferences.Select(dsr => dsr.SyntaxTree.FilePath).ToList(), DocumentationId = symbol.GetDocumentationCommentId(), DocumentationXml = symbol.GetDocumentationCommentXml(), Documentation = Documentation.Read(symbol.GetDocumentationCommentXml()), Modifier = ModifierEnumExtensions.Modifier(symbol.DeclaredAccessibility), IsAbstract = symbol.IsAbstract, IsExtern = symbol.IsExtern, IsSealed = symbol.IsSealed, IsStatic = symbol.IsStatic, IsOverride = symbol.IsOverride, IsVirtual = symbol.IsVirtual, IsReadOnly = symbol.IsReadOnly, IsWriteOnly = symbol.IsWriteOnly, IsIndexer = symbol.IsIndexer, TypeRef = TypeRef.GetOrCreate(symbol.Type, root), IsNew = symbol.GetIsNew(), OverridesSymbol = symbol.OverriddenProperty, ExplicitInterfaceImplementationMemberSymbol = symbol.ExplicitInterfaceImplementations != null && symbol.ExplicitInterfaceImplementations.Length > 0 ? symbol.ExplicitInterfaceImplementations[0] : null }; var propertyModifier = ModifierEnumExtensions.Modifier(symbol.DeclaredAccessibility); var getterModifier = ModifierEnumExtensions.Modifier(symbol.GetMethod?.DeclaredAccessibility ?? symbol.DeclaredAccessibility); var setterModifier = ModifierEnumExtensions.Modifier(symbol.SetMethod?.DeclaredAccessibility ?? symbol.DeclaredAccessibility); if (getterModifier != propertyModifier) { p.GetterModifier = getterModifier.ToModifierString(); } if (setterModifier != propertyModifier) { p.SetterModifier = setterModifier.ToModifierString(); } if (symbol.Parameters != null && symbol.Parameters.Length > 0) { //Process the indexer parameters (the only property kind with parameters p.Parameters = GetMethodParameters(symbol.Parameters, root); p.Name = p.Name.Replace("[]", $"[{string.Join(", ", p.Parameters.Select(param => param.TypeRef.ApplySpecialName(false)))}]"); } p.SetAttributes(root); type.ContentMembers.Add(p); Console.WriteLine($"{new string(' ', level)} read as {p}"); }