Ejemplo n.º 1
0
        private void AnalyzeMemberAccessExpression(SyntaxNodeAnalysisContext context)
        {
            if (!AnalyzerHelper.IsAssemblyNeedAnalyze(context.Compilation.AssemblyName, AnalyzeAssembly.AllHotfix))
            {
                return;
            }

            if (!(context.Node is MemberAccessExpressionSyntax memberAccessExpressionSyntax))
            {
                return;
            }

            // 筛选出 AddChild函数syntax
            string methodName = memberAccessExpressionSyntax.Name.Identifier.Text;

            if (!AddChildMethods.Contains(methodName))
            {
                return;
            }

            if (!(memberAccessExpressionSyntax?.Parent is InvocationExpressionSyntax invocationExpressionSyntax) ||
                !(context.SemanticModel.GetSymbolInfo(invocationExpressionSyntax).Symbol is IMethodSymbol addChildMethodSymbol))
            {
                return;
            }

            // 获取AddChild函数的调用者类型
            ITypeSymbol?parentTypeSymbol = memberAccessExpressionSyntax.GetMemberAccessSyntaxParentType(context.SemanticModel);

            if (parentTypeSymbol == null)
            {
                return;
            }

            // 只检查Entity的子类
            if (parentTypeSymbol.BaseType?.ToString() != EntityType)
            {
                return;
            }

            // 获取实体类 ChildType标签的约束类型
            INamedTypeSymbol?availableChildTypeSymbol = null;
            bool             hasChildTypeAttribute    = false;

            foreach (AttributeData?attributeData in parentTypeSymbol.GetAttributes())
            {
                if (attributeData.AttributeClass?.Name == "ChildTypeAttribute")
                {
                    hasChildTypeAttribute = true;
                    if (!(attributeData.ConstructorArguments[0].Value is INamedTypeSymbol s))
                    {
                        continue;
                    }

                    availableChildTypeSymbol = s;
                }
            }

            if (hasChildTypeAttribute && (availableChildTypeSymbol == null))
            {
                return;
            }

            // 获取 child实体类型
            ISymbol?childTypeSymbol = null;

            // addChild为泛型调用
            if (addChildMethodSymbol.IsGenericMethod)
            {
                GenericNameSyntax?genericNameSyntax = memberAccessExpressionSyntax?.GetFirstChild <GenericNameSyntax>();

                TypeArgumentListSyntax?typeArgumentList = genericNameSyntax?.GetFirstChild <TypeArgumentListSyntax>();

                IdentifierNameSyntax?childTypeSyntax = typeArgumentList?.GetFirstChild <IdentifierNameSyntax>();

                if (childTypeSyntax == null)
                {
                    Diagnostic diagnostic = Diagnostic.Create(Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation());
                    context.ReportDiagnostic(diagnostic);
                    throw new Exception("childTypeSyntax==null");
                }

                childTypeSymbol = context.SemanticModel.GetSymbolInfo(childTypeSyntax).Symbol;
            }
            // addChild为非泛型调用
            else
            {
                SyntaxNode?firstArgumentSyntax = invocationExpressionSyntax.GetFirstChild <ArgumentListSyntax>()?.GetFirstChild <ArgumentSyntax>()
                                                 ?.ChildNodes().First();
                if (firstArgumentSyntax == null)
                {
                    Diagnostic diagnostic = Diagnostic.Create(Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation());
                    context.ReportDiagnostic(diagnostic);
                    return;
                }

                ISymbol?firstArgumentSymbol = context.SemanticModel.GetSymbolInfo(firstArgumentSyntax).Symbol;

                if (firstArgumentSymbol is ILocalSymbol childLocalSymbol)
                {
                    childTypeSymbol = childLocalSymbol.Type;
                }
                else if (firstArgumentSymbol is IParameterSymbol childParamaterSymbol)
                {
                    childTypeSymbol = childParamaterSymbol.Type;
                }
                else if (firstArgumentSymbol is IMethodSymbol methodSymbol)
                {
                    childTypeSymbol = methodSymbol.ReturnType;
                }
                else if (firstArgumentSymbol is IFieldSymbol fieldSymbol)
                {
                    childTypeSymbol = fieldSymbol.Type;
                }
                else if (firstArgumentSymbol is IPropertySymbol propertySymbol)
                {
                    childTypeSymbol = propertySymbol.Type;
                }
                else if (firstArgumentSymbol != null)
                {
                    Diagnostic diagnostic = Diagnostic.Create(Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation(),
                                                              firstArgumentSymbol.Name, parentTypeSymbol.Name);
                    context.ReportDiagnostic(diagnostic);
                    return;
                }
                else
                {
                    Diagnostic diagnostic = Diagnostic.Create(Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation(),
                                                              firstArgumentSyntax.GetText(), parentTypeSymbol.Name);
                    context.ReportDiagnostic(diagnostic);
                    return;
                }
            }

            if (childTypeSymbol == null)
            {
                return;
            }


            // 判断child类型是否属于约束类型
            if (availableChildTypeSymbol?.ToString() == childTypeSymbol.ToString())
            {
                return;
            }

            {
                Diagnostic diagnostic = Diagnostic.Create(Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation(), childTypeSymbol?.Name,
                                                          parentTypeSymbol?.Name);
                context.ReportDiagnostic(diagnostic);
            }
        }
Ejemplo n.º 2
0
 /// <summary>
 /// Replace any named type in the symbol list with its instance constructors.
 /// Construct all candidates with the implicitly-declared CrefTypeParameterSymbols.
 /// </summary>
 private void GetCrefOverloadResolutionCandidates(ImmutableArray <Symbol> symbols, int arity, TypeArgumentListSyntax?typeArgumentListSyntax, ArrayBuilder <Symbol> candidates)
 {
     foreach (Symbol candidate in symbols)
     {
         Symbol          constructedCandidate     = ConstructWithCrefTypeParameters(arity, typeArgumentListSyntax, candidate);
         NamedTypeSymbol?constructedCandidateType = constructedCandidate as NamedTypeSymbol;
         if ((object?)constructedCandidateType == null)
         {
             // Construct before overload resolution so the signatures will match.
             candidates.Add(constructedCandidate);
         }
         else
         {
             candidates.AddRange(constructedCandidateType.InstanceConstructors);
         }
     }
 }
Ejemplo n.º 3
0
        /// <summary>
        /// At this point, we have a list of viable symbols and no parameter list with which to perform
        /// overload resolution.  We'll just return the first symbol, giving a diagnostic if there are
        /// others.
        /// Caveat: If there are multiple candidates and only one is from source, then the source symbol
        /// wins and no diagnostic is reported.
        /// </summary>
        private ImmutableArray <Symbol> ProcessParameterlessCrefMemberLookupResults(
            ImmutableArray <Symbol> symbols,
            int arity,
            MemberCrefSyntax memberSyntax,
            TypeArgumentListSyntax?typeArgumentListSyntax,
            out Symbol?ambiguityWinner,
            BindingDiagnosticBag diagnostics)
        {
            // If the syntax indicates arity zero, then we match methods of any arity.
            // However, if there are both generic and non-generic methods, then the
            // generic methods should be ignored.
            if (symbols.Length > 1 && arity == 0)
            {
                bool hasNonGenericMethod = false;
                bool hasGenericMethod    = false;
                foreach (Symbol s in symbols)
                {
                    if (s.Kind != SymbolKind.Method)
                    {
                        continue;
                    }

                    if (((MethodSymbol)s).Arity == 0)
                    {
                        hasNonGenericMethod = true;
                    }
                    else
                    {
                        hasGenericMethod = true;
                    }

                    if (hasGenericMethod && hasNonGenericMethod)
                    {
                        break; //Nothing else to be learned.
                    }
                }

                if (hasNonGenericMethod && hasGenericMethod)
                {
                    symbols = symbols.WhereAsArray(s =>
                                                   s.Kind != SymbolKind.Method || ((MethodSymbol)s).Arity == 0);
                }
            }

            Debug.Assert(!symbols.IsEmpty);

            Symbol symbol = symbols[0];

            // If there's ambiguity, prefer source symbols.
            // Logic is similar to ResultSymbol, but separate because the error handling is totally different.
            if (symbols.Length > 1)
            {
                // Size is known, but IndexOfSymbolFromCurrentCompilation expects a builder.
                ArrayBuilder <Symbol> unwrappedSymbols = ArrayBuilder <Symbol> .GetInstance(symbols.Length);

                foreach (Symbol wrapped in symbols)
                {
                    unwrappedSymbols.Add(UnwrapAliasNoDiagnostics(wrapped));
                }

                BestSymbolInfo secondBest;
                BestSymbolInfo best = GetBestSymbolInfo(unwrappedSymbols, out secondBest);

                Debug.Assert(!best.IsNone);
                Debug.Assert(!secondBest.IsNone);

                unwrappedSymbols.Free();

                int symbolIndex = 0;

                if (best.IsFromCompilation)
                {
                    symbolIndex = best.Index;
                    symbol      = symbols[symbolIndex]; // NOTE: symbols, not unwrappedSymbols.
                }

                if (symbol.Kind == SymbolKind.TypeParameter)
                {
                    CrefSyntax crefSyntax = GetRootCrefSyntax(memberSyntax);
                    diagnostics.Add(ErrorCode.WRN_BadXMLRefTypeVar, crefSyntax.Location, crefSyntax.ToString());
                }
                else if (secondBest.IsFromCompilation == best.IsFromCompilation)
                {
                    CrefSyntax crefSyntax = GetRootCrefSyntax(memberSyntax);
                    int        otherIndex = symbolIndex == 0 ? 1 : 0;
                    diagnostics.Add(ErrorCode.WRN_AmbiguousXMLReference, crefSyntax.Location, crefSyntax.ToString(), symbol, symbols[otherIndex]);

                    ambiguityWinner = ConstructWithCrefTypeParameters(arity, typeArgumentListSyntax, symbol);
                    return(symbols.SelectAsArray(sym => ConstructWithCrefTypeParameters(arity, typeArgumentListSyntax, sym)));
                }
            }
            else if (symbol.Kind == SymbolKind.TypeParameter)
            {
                CrefSyntax crefSyntax = GetRootCrefSyntax(memberSyntax);
                diagnostics.Add(ErrorCode.WRN_BadXMLRefTypeVar, crefSyntax.Location, crefSyntax.ToString());
            }

            ambiguityWinner = null;
            return(ImmutableArray.Create <Symbol>(ConstructWithCrefTypeParameters(arity, typeArgumentListSyntax, symbol)));
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Given a list of viable lookup results (based on the name, arity, and containing symbol),
        /// attempt to select one.
        /// </summary>
        private ImmutableArray <Symbol> ProcessCrefMemberLookupResults(
            ImmutableArray <Symbol> symbols,
            int arity,
            MemberCrefSyntax memberSyntax,
            TypeArgumentListSyntax?typeArgumentListSyntax,
            BaseCrefParameterListSyntax?parameterListSyntax,
            out Symbol?ambiguityWinner,
            BindingDiagnosticBag diagnostics)
        {
            Debug.Assert(!symbols.IsEmpty);

            if (parameterListSyntax == null)
            {
                return(ProcessParameterlessCrefMemberLookupResults(symbols, arity, memberSyntax, typeArgumentListSyntax, out ambiguityWinner, diagnostics));
            }

            ArrayBuilder <Symbol> candidates = ArrayBuilder <Symbol> .GetInstance();

            GetCrefOverloadResolutionCandidates(symbols, arity, typeArgumentListSyntax, candidates);

            ImmutableArray <ParameterSymbol> parameterSymbols = BindCrefParameters(parameterListSyntax, diagnostics);
            ImmutableArray <Symbol>          results          = PerformCrefOverloadResolution(candidates, parameterSymbols, arity, memberSyntax, out ambiguityWinner, diagnostics);

            candidates.Free();

            // NOTE: This diagnostic is just a hint that might help fix a broken cref, so don't do
            // any work unless there are no viable candidates.
            if (results.Length == 0)
            {
                for (int i = 0; i < parameterSymbols.Length; i++)
                {
                    if (ContainsNestedTypeOfUnconstructedGenericType(parameterSymbols[i].Type))
                    {
                        // This warning is new in Roslyn, because our better-defined semantics for
                        // cref lookup disallow some things that were possible in dev12.
                        //
                        // Consider the following code:
                        //
                        //   public class C<T>
                        //   {
                        //       public class Inner { }
                        //
                        //       public void M(Inner i) { }
                        //
                        //       /// <see cref="M"/>
                        //       /// <see cref="C{T}.M"/>
                        //       /// <see cref="C{Q}.M"/>
                        //       /// <see cref="C{Q}.M(C{Q}.Inner)"/>
                        //       /// <see cref="C{Q}.M(Inner)"/> // WRN_UnqualifiedNestedTypeInCref
                        //       public void N() { }
                        //   }
                        //
                        // Dev12 binds all of the crefs as "M:C`1.M(C{`0}.Inner)".
                        // Roslyn accepts all but the last.  The issue is that the context for performing
                        // the lookup is not C<Q>, but C<T>.  Consequently, Inner binds to C<T>.Inner and
                        // then overload resolution fails because C<T>.Inner does not match C<Q>.Inner,
                        // the parameter type of C<Q>.M.  Since we could not agree that the old behavior
                        // was desirable (other than for backwards compatibility) and since mimicking it
                        // would have been expensive, we settled on introducing a new warning that at
                        // least hints to the user how then can work around the issue (i.e. by qualifying
                        // Inner as C{Q}.Inner).  Additional details are available in DevDiv #743425.
                        //
                        // CONSIDER: We could actually put the qualified form in the warning message,
                        // but that would probably just make it more frustrating (i.e. if the compiler
                        // knows exactly what I mean, why do I have to type it).
                        //
                        // NOTE: This is not a great location (whole parameter instead of problematic type),
                        // but it's better than nothing.
                        diagnostics.Add(ErrorCode.WRN_UnqualifiedNestedTypeInCref, parameterListSyntax.Parameters[i].Location);
                        break;
                    }
                }
            }

            return(results);
        }
Ejemplo n.º 5
0
        private void AnalyzeMemberAccessExpression(SyntaxNodeAnalysisContext context)
        {
            if (!AnalyzerHelper.IsAssemblyNeedAnalyze(context.Compilation.AssemblyName, AnalyzeAssembly.All))
            {
                return;
            }

            if (!(context.Node is MemberAccessExpressionSyntax memberAccessExpressionSyntax))
            {
                return;
            }

            // 筛选出 Component函数syntax
            string methodName = memberAccessExpressionSyntax.Name.Identifier.Text;

            if (!Definition.ComponentMethod.Contains(methodName))
            {
                return;
            }

            if (!(memberAccessExpressionSyntax?.Parent is InvocationExpressionSyntax invocationExpressionSyntax) ||
                !(context.SemanticModel.GetSymbolInfo(invocationExpressionSyntax).Symbol is IMethodSymbol addComponentMethodSymbol))
            {
                return;
            }

            // 获取AComponent函数的调用者类型
            ITypeSymbol?parentTypeSymbol = memberAccessExpressionSyntax.GetMemberAccessSyntaxParentType(context.SemanticModel);

            if (parentTypeSymbol == null)
            {
                return;
            }

            // 对于Entity基类会报错 除非标记了EnableAccessEntiyChild
            if (parentTypeSymbol.ToString() == Definition.EntityType)
            {
                HandleAcessEntityChild(context);
                return;
            }

            // 非Entity的子类 跳过
            if (parentTypeSymbol.BaseType?.ToString() != Definition.EntityType)
            {
                return;
            }

            // 获取 component实体类型
            ISymbol?componentTypeSymbol = null;

            // Component为泛型调用
            if (addComponentMethodSymbol.IsGenericMethod)
            {
                GenericNameSyntax?genericNameSyntax = memberAccessExpressionSyntax?.GetFirstChild <GenericNameSyntax>();

                TypeArgumentListSyntax?typeArgumentList = genericNameSyntax?.GetFirstChild <TypeArgumentListSyntax>();

                var componentTypeSyntax = typeArgumentList?.Arguments.First();

                if (componentTypeSyntax == null)
                {
                    Diagnostic diagnostic = Diagnostic.Create(EntityComponentAnalyzerRule.Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation());
                    context.ReportDiagnostic(diagnostic);
                    throw new Exception("componentTypeSyntax==null");
                }

                componentTypeSymbol = context.SemanticModel.GetSymbolInfo(componentTypeSyntax).Symbol;
            }
            //Component为非泛型调用
            else
            {
                SyntaxNode?firstArgumentSyntax = invocationExpressionSyntax.GetFirstChild <ArgumentListSyntax>()?.GetFirstChild <ArgumentSyntax>()
                                                 ?.ChildNodes().First();
                if (firstArgumentSyntax == null)
                {
                    Diagnostic diagnostic = Diagnostic.Create(EntityComponentAnalyzerRule.Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation());
                    context.ReportDiagnostic(diagnostic);
                    return;
                }

                // 参数为typeOf时 提取Type类型
                if (firstArgumentSyntax is TypeOfExpressionSyntax typeOfExpressionSyntax)
                {
                    firstArgumentSyntax = typeOfExpressionSyntax.Type;
                }

                ISymbol?firstArgumentSymbol = context.SemanticModel.GetSymbolInfo(firstArgumentSyntax).Symbol;

                if (firstArgumentSymbol is ILocalSymbol childLocalSymbol)
                {
                    componentTypeSymbol = childLocalSymbol.Type;
                }
                else if (firstArgumentSymbol is IParameterSymbol childParamaterSymbol)
                {
                    componentTypeSymbol = childParamaterSymbol.Type;
                }
                else if (firstArgumentSymbol is IMethodSymbol methodSymbol)
                {
                    componentTypeSymbol = methodSymbol.ReturnType;
                }
                else if (firstArgumentSymbol is IFieldSymbol fieldSymbol)
                {
                    componentTypeSymbol = fieldSymbol.Type;
                }
                else if (firstArgumentSymbol is IPropertySymbol propertySymbol)
                {
                    componentTypeSymbol = propertySymbol.Type;
                }
                else if (firstArgumentSymbol is INamedTypeSymbol namedTypeSymbol)
                {
                    componentTypeSymbol = namedTypeSymbol;
                }
                else if (firstArgumentSymbol is ITypeParameterSymbol)
                {
                    // 忽略typeof(T)参数类型
                    return;
                }
                else if (firstArgumentSymbol != null)
                {
                    Diagnostic diagnostic = Diagnostic.Create(EntityComponentAnalyzerRule.Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation(),
                                                              firstArgumentSymbol.Name, parentTypeSymbol.Name);
                    context.ReportDiagnostic(diagnostic);
                    return;
                }
                else
                {
                    Diagnostic diagnostic = Diagnostic.Create(EntityComponentAnalyzerRule.Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation(),
                                                              firstArgumentSyntax.GetText(), parentTypeSymbol.Name);
                    context.ReportDiagnostic(diagnostic);
                    return;
                }
            }

            if (componentTypeSymbol == null)
            {
                return;
            }

            // 忽略 component类型为泛型类型
            if (componentTypeSymbol is ITypeParameterSymbol typeParameterSymbol)
            {
                return;
            }

            // 忽略 Type参数
            if (componentTypeSymbol.ToString() == "System.Type")
            {
                return;
            }

            // 组件类型为Entity时 忽略检查
            if (componentTypeSymbol.ToString() == Definition.EntityType)
            {
                return;
            }

            // 判断component类型是否属于约束类型

            //获取component类的parentType标记数据
            INamedTypeSymbol?availableParentTypeSymbol = null;
            bool             hasParentTypeAttribute    = false;

            foreach (AttributeData?attributeData in componentTypeSymbol.GetAttributes())
            {
                if (attributeData.AttributeClass?.ToString() == Definition.ComponentOfAttribute)
                {
                    hasParentTypeAttribute = true;
                    if (attributeData.ConstructorArguments[0].Value is INamedTypeSymbol typeSymbol)
                    {
                        availableParentTypeSymbol = typeSymbol;
                        break;
                    }
                }
            }

            if (hasParentTypeAttribute && availableParentTypeSymbol == null)
            {
                return;
            }

            // 符合约束条件 通过检查
            if (availableParentTypeSymbol != null && availableParentTypeSymbol.ToString() == parentTypeSymbol.ToString())
            {
                return;
            }

            {
                Diagnostic diagnostic = Diagnostic.Create(EntityComponentAnalyzerRule.Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation(), componentTypeSymbol?.Name,
                                                          parentTypeSymbol?.Name);
                context.ReportDiagnostic(diagnostic);
            }
        }
Ejemplo n.º 6
0
        private void AnalyzeMemberAccessExpression(SyntaxNodeAnalysisContext context)
        {
            if (!AnalyzerHelper.IsAssemblyNeedAnalyze(context.Compilation.AssemblyName, AnalyzeAssembly.All))
            {
                return;
            }

            if (!(context.Node is MemberAccessExpressionSyntax memberAccessExpressionSyntax))
            {
                return;
            }

            // 筛选出 AddChild函数syntax
            string methodName = memberAccessExpressionSyntax.Name.Identifier.Text;

            if (!Definition.AddChildMethods.Contains(methodName))
            {
                return;
            }

            if (!(memberAccessExpressionSyntax?.Parent is InvocationExpressionSyntax invocationExpressionSyntax) ||
                !(context.SemanticModel.GetSymbolInfo(invocationExpressionSyntax).Symbol is IMethodSymbol addChildMethodSymbol))
            {
                return;
            }

            // 获取AddChild函数的调用者类型
            ITypeSymbol?parentTypeSymbol = memberAccessExpressionSyntax.GetMemberAccessSyntaxParentType(context.SemanticModel);

            if (parentTypeSymbol == null)
            {
                return;
            }


            // 对于Entity基类会报错 除非标记了EnableAccessEntiyChild
            if (parentTypeSymbol.ToString() == Definition.EntityType)
            {
                HandleAcessEntityChild(context);
                return;
            }

            // 非Entity的子类 跳过
            if (parentTypeSymbol.BaseType?.ToString() != Definition.EntityType)
            {
                return;
            }


            // 获取 child实体类型
            ISymbol?childTypeSymbol = null;

            // addChild为泛型调用
            if (addChildMethodSymbol.IsGenericMethod)
            {
                GenericNameSyntax?genericNameSyntax = memberAccessExpressionSyntax?.GetFirstChild <GenericNameSyntax>();

                TypeArgumentListSyntax?typeArgumentList = genericNameSyntax?.GetFirstChild <TypeArgumentListSyntax>();

                var childTypeSyntax = typeArgumentList?.Arguments.First();

                if (childTypeSyntax == null)
                {
                    Diagnostic diagnostic = Diagnostic.Create(AddChildTypeAnalyzerRule.Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation());
                    context.ReportDiagnostic(diagnostic);
                    throw new Exception("childTypeSyntax==null");
                }

                childTypeSymbol = context.SemanticModel.GetSymbolInfo(childTypeSyntax).Symbol;
            }
            // addChild为非泛型调用
            else
            {
                SyntaxNode?firstArgumentSyntax = invocationExpressionSyntax.GetFirstChild <ArgumentListSyntax>()?.GetFirstChild <ArgumentSyntax>()
                                                 ?.ChildNodes().First();
                if (firstArgumentSyntax == null)
                {
                    Diagnostic diagnostic = Diagnostic.Create(AddChildTypeAnalyzerRule.Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation());
                    context.ReportDiagnostic(diagnostic);
                    return;
                }

                ISymbol?firstArgumentSymbol = context.SemanticModel.GetSymbolInfo(firstArgumentSyntax).Symbol;

                if (firstArgumentSymbol is ILocalSymbol childLocalSymbol)
                {
                    childTypeSymbol = childLocalSymbol.Type;
                }
                else if (firstArgumentSymbol is IParameterSymbol childParamaterSymbol)
                {
                    childTypeSymbol = childParamaterSymbol.Type;
                }
                else if (firstArgumentSymbol is IMethodSymbol methodSymbol)
                {
                    childTypeSymbol = methodSymbol.ReturnType;
                }
                else if (firstArgumentSymbol is IFieldSymbol fieldSymbol)
                {
                    childTypeSymbol = fieldSymbol.Type;
                }
                else if (firstArgumentSymbol is IPropertySymbol propertySymbol)
                {
                    childTypeSymbol = propertySymbol.Type;
                }
                else if (firstArgumentSymbol != null)
                {
                    Diagnostic diagnostic = Diagnostic.Create(AddChildTypeAnalyzerRule.Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation(),
                                                              firstArgumentSymbol.Name, parentTypeSymbol.Name);
                    context.ReportDiagnostic(diagnostic);
                    return;
                }
                else
                {
                    Diagnostic diagnostic = Diagnostic.Create(AddChildTypeAnalyzerRule.Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation(),
                                                              firstArgumentSyntax.GetText(), parentTypeSymbol.Name);
                    context.ReportDiagnostic(diagnostic);
                    return;
                }
            }

            if (childTypeSymbol == null)
            {
                return;
            }

            // 忽略 child类型为泛型类型
            if (childTypeSymbol is ITypeParameterSymbol typeParameterSymbol)
            {
                return;
            }

            // 获取ChildOf标签的约束类型

            if (!(childTypeSymbol is ITypeSymbol childType))
            {
                throw new Exception($"{childTypeSymbol} 不是typeSymbol");
            }

            INamedTypeSymbol?availableParentType = null;
            bool             hasAttribute        = false;

            foreach (AttributeData?attributeData in childType.GetAttributes())
            {
                if (attributeData.AttributeClass?.ToString() == Definition.ChildOfAttribute)
                {
                    hasAttribute        = true;
                    availableParentType = attributeData.ConstructorArguments[0].Value as INamedTypeSymbol;
                    break;
                }
            }

            if (hasAttribute && availableParentType == null)
            {
                return;
            }

            // 判断父级类型是否属于child约束的父级类型
            if (availableParentType?.ToString() == parentTypeSymbol.ToString())
            {
                return;
            }

            {
                Diagnostic diagnostic = Diagnostic.Create(AddChildTypeAnalyzerRule.Rule, memberAccessExpressionSyntax?.Name.Identifier.GetLocation(), childTypeSymbol?.Name,
                                                          parentTypeSymbol?.Name);
                context.ReportDiagnostic(diagnostic);
            }
        }