/// <summary> /// Prepares the <see cref="FieldMemberBuilder"/> 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 BuildField(IFieldSymbol symbol, RootMemberBuilder root, TypeMemberBuilder type, int level) { if (symbol.IsImplicitlyDeclared) { return; } if (symbol.GetAttributes().Any(a => a.AttributeClassString() == "System.Runtime.CompilerServices.CompilerGeneratedAttribute")) { return; } var f = new FieldMemberBuilder() { Name = symbol.Name, NameBase = symbol.Name, 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, IsConst = symbol.IsConst, IsReadOnly = symbol.IsReadOnly, IsVolatile = symbol.IsVolatile, ConstantValue = symbol.ConstantValue, TypeRef = TypeRef.GetOrCreate(symbol.Type, root), IsNew = symbol.GetIsNew() }; f.SetAttributes(root); type.ContentMembers.Add(f); Console.WriteLine($"{new string(' ', level)} read as {f}"); }
/// <summary> /// フィールドの処理 /// </summary> private void ProcessField(StringBuilder source, IFieldSymbol fieldSymbol, ISymbol attributeSymbol) { string fieldName = fieldSymbol.Name; ITypeSymbol fieldType = fieldSymbol.Type; AttributeData attributeData = fieldSymbol.GetAttributes().Single(ad => ad.AttributeClass.Equals(attributeSymbol, SymbolEqualityComparer.Default)); TypedConstant overridenNameOpt = attributeData.NamedArguments.SingleOrDefault(kvp => kvp.Key == "PropertyName").Value; string propertyName = chooseName(fieldName, overridenNameOpt); if (propertyName.Length == 0 || propertyName == fieldName) { //TODO: プロパティ名が空か、フィールド名と同名を指定した場合、自動生成できません。 return; } // サマリーを抽出します。 var xmlDocument = new XmlDocument(); var xmlComment = fieldSymbol.GetDocumentationCommentXml(); if (!string.IsNullOrEmpty(xmlComment)) { xmlDocument.LoadXml(xmlComment); var summaryNode = xmlDocument.SelectSingleNode("member/summary"); var summary = summaryNode?.InnerText?.Replace("\r\n", ""); if (!string.IsNullOrWhiteSpace(summary)) { source.Append($@" /// <summary> /// {summary} /// </summary>"); } } source.Append($@" public {fieldType} {propertyName} {{ get => this.{fieldName}; set {{ this.{fieldName} = value; this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof({propertyName}))); }} }} "); string chooseName(string fieldName, TypedConstant overridenNameOpt) { if (!overridenNameOpt.IsNull) { return(overridenNameOpt.Value.ToString()); } fieldName = fieldName.TrimStart('_'); if (fieldName.Length == 0) { return(string.Empty); } if (fieldName.Length == 1) { return(fieldName.ToUpper()); } return(fieldName.Substring(0, 1).ToUpper() + fieldName.Substring(1)); } }
protected override IEnumerable <Diagnostic> AnalyzeField(IFieldSymbol symbol) => ShallAnalyzeField(symbol) ? AnalyzeField(symbol, symbol.GetDocumentationCommentXml()) : Enumerable.Empty <Diagnostic>();