internal static void VerifyType(ContextReporter context, Location reportLocation, ITypeSymbol type, HashSet <ITypeSymbol> alreadyAnalyzed)
        {
            if (type.TypeKind == TypeKind.Array)
            {
                var array = type as IArrayTypeSymbol;
                VerifyType(context, reportLocation, array.ElementType, alreadyAnalyzed);
                return;
            }

            var namedTypeSymbol = (type as INamedTypeSymbol);

            if (namedTypeSymbol != null && namedTypeSymbol.IsGenericType)
            {
                foreach (var item in namedTypeSymbol.TypeArguments)
                {
                    VerifyType(context, reportLocation, item, alreadyAnalyzed);
                }
                return;
            }

            if (type.TypeKind == TypeKind.Class || type.TypeKind == TypeKind.Struct)
            {
                if (type.Locations[0].Kind == LocationKind.MetadataFile)
                {
                    return;
                }

                if (!alreadyAnalyzed.Add(type))
                {
                    return;
                }

                var typeLocation = type.Locations[0];
                var members      = type.GetMembers().Where(x => x is IFieldSymbol || x is IPropertySymbol)
                                   .Where(x => x.CanBeReferencedByName)
                                   .ToArray();
                if (members.Length != 0)
                {
                    var hasDiagnostic = false;
                    foreach (var member in members)
                    {
                        if (!hasDiagnostic)
                        {
                            hasDiagnostic = VerifyMember(context, reportLocation, member, typeLocation);
                        }

                        VerifyType(context, reportLocation, (member as IFieldSymbol)?.Type ?? (member as IPropertySymbol)?.Type ?? null, alreadyAnalyzed);
                    }

                    if (!hasDiagnostic)
                    {
                        var dataContract = type.GetAttributes().FirstOrDefault(y => y.AttributeClass.ToString() == "System.Runtime.Serialization.DataContractAttribute");
                        if (dataContract == null)
                        {
                            context.ReportDiagnostic(Diagnostic.Create(SerializeTypeMustBeDataContract, reportLocation, new[] { typeLocation }, type.ToString()));
                        }
                    }
                }
            }
        }
        static void Analyze(SyntaxNodeAnalysisContext context)
        {
            var model = context.SemanticModel;

            var classDeclaration = context.Node as ClassDeclarationSyntax;
            if (classDeclaration == null) return;

            var declaredSymbol = model.GetDeclaredSymbol(classDeclaration);
            if (declaredSymbol == null) return;
            if (declaredSymbol.IsAbstract) return;

            var reporter = new ContextReporter(context);
            var hub = declaredSymbol.FindBaseTargetType("PhotonWire.Server.Hub<T>");
            if (hub != null)
            {
                // Verify HubClient
                var clientType = hub.TypeArguments[0];
                VerifyTypeMethods(reporter, clientType);
            }
            else
            {
                // check ServerHub, ReceiveServerHub
                hub = declaredSymbol.FindBaseTargetType("PhotonWire.Server.ServerToServer.ServerHub");
                if (hub == null)
                {
                    hub = declaredSymbol.FindBaseTargetType("PhotonWire.Server.ServerToServer.ReceiveServerHub");
                    if (hub == null)
                    {
                        return; // is not hub method, end analyze
                    }
                }
            }

            VerifyTypeMethods(reporter, declaredSymbol);
        }
        internal static void VerifyTypeMethods(ContextReporter context, ITypeSymbol type)
        {
            var methods = type.GetMembers()
                          .OfType <IMethodSymbol>()
                          .Where(x => x.MethodKind == MethodKind.Ordinary)
                          .Where(x => x.DeclaredAccessibility == Accessibility.Public)
                          .Where(x => !x.IsStatic)
                          .ToArray();

            var alreadyAnalyzed = new HashSet <ITypeSymbol>();

            foreach (var method in methods)
            {
                var methodDecl = method.DeclaringSyntaxReferences[0].GetSyntax() as MethodDeclarationSyntax;
                if (methodDecl == null)
                {
                    return;
                }

                VerifyType(context, methodDecl.ReturnType.GetLocation(), method.ReturnType, alreadyAnalyzed);
                foreach (var item in method.Parameters.Zip(methodDecl.ParameterList.Parameters, (symbol, syntax) => new { symbol, syntax }))
                {
                    VerifyType(context, item.syntax.Type.GetLocation(), item.symbol.Type, alreadyAnalyzed);
                }
            }
        }
        static bool VerifyMember(ContextReporter context, Location reportLocation, ISymbol member, Location typeLocation)
        {
            if (member.Locations[0].Kind == LocationKind.MetadataFile)
            {
                return(false); // in metadata, I don't know...
            }

            if (member is IPropertySymbol)
            {
                // get only property
                var prop = member as IPropertySymbol;
                if (prop.SetMethod == null)
                {
                    return(false);
                }
            }

            var attr = member.GetAttributes();

            if (attr.Length == 0)
            {
                context.ReportDiagnostic(Diagnostic.Create(SerializeTypeMustBeDataContract, reportLocation, new[] { typeLocation }, member.ContainingType.ToString()));
                return(true);
            }

            if (attr.Any(x => x.AttributeClass.ToString() == typeof(System.Runtime.Serialization.IgnoreDataMemberAttribute).FullName))
            {
                return(false);
            }

            var dataMemberAttr = attr.FirstOrDefault(y => y.AttributeClass.ToString() == typeof(System.Runtime.Serialization.DataMemberAttribute).FullName);

            if (dataMemberAttr == null)
            {
                context.ReportDiagnostic(Diagnostic.Create(SerializeTypeMustBeDataContract, reportLocation, new[] { typeLocation }, member.ContainingType.ToString()));
                return(true);
            }

            var hasOrder = dataMemberAttr.NamedArguments.Any(x => x.Key == "Order");

            if (!hasOrder)
            {
                context.ReportDiagnostic(Diagnostic.Create(SerializeTypeMustBeDataContract, reportLocation, new[] { typeLocation }, member.ContainingType.ToString()));
                return(true);
            }

            return(false);
        }
        static void Analyze(SyntaxNodeAnalysisContext context)
        {
            var model = context.SemanticModel;

            var classDeclaration = context.Node as ClassDeclarationSyntax;

            if (classDeclaration == null)
            {
                return;
            }

            var declaredSymbol = model.GetDeclaredSymbol(classDeclaration);

            if (declaredSymbol == null)
            {
                return;
            }
            if (declaredSymbol.IsAbstract)
            {
                return;
            }

            var reporter = new ContextReporter(context);
            var hub      = declaredSymbol.FindBaseTargetType("PhotonWire.Server.Hub<T>");

            if (hub != null)
            {
                // Verify HubClient
                var clientType = hub.TypeArguments[0];
                VerifyTypeMethods(reporter, clientType);
            }
            else
            {
                // check ServerHub, ReceiveServerHub
                hub = declaredSymbol.FindBaseTargetType("PhotonWire.Server.ServerToServer.ServerHub");
                if (hub == null)
                {
                    hub = declaredSymbol.FindBaseTargetType("PhotonWire.Server.ServerToServer.ReceiveServerHub");
                    if (hub == null)
                    {
                        return; // is not hub method, end analyze
                    }
                }
            }

            VerifyTypeMethods(reporter, declaredSymbol);
        }
Пример #6
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false) as CompilationUnitSyntax;

            var model = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);

            var targetNode = root.FindNode(context.Span);
            var targetType = model.GetTypeInfo(targetNode).Type;

            if (targetType == null)
            {
                return;
            }

            if (targetType.GetMembers().Length == 0)
            {
                return;
            }

            var reporter = new ContextReporter();

            SerializeTypeMustBeDataContractAnalyzer.VerifyType(reporter, null, targetType, new System.Collections.Generic.HashSet <ITypeSymbol>());

            foreach (var item in reporter.Diagnostics)
            {
                var location     = item.AdditionalLocations[0];
                var targetSyntax = location.SourceTree.GetCompilationUnitRoot().FindNode(location.SourceSpan) as TypeDeclarationSyntax;

                var targetDocument      = context.Document.Project.Solution.GetDocument(targetSyntax.SyntaxTree);
                var targetSemanticModel = await targetDocument.GetSemanticModelAsync().ConfigureAwait(false);

                var targetRoot = await targetDocument.GetSyntaxRootAsync().ConfigureAwait(false) as CompilationUnitSyntax;

                var action = CodeAction.Create("Add DataMember with Order", c => AddDataMemberWithOrder(targetDocument, targetSemanticModel, targetRoot, targetSyntax, c), location.ToString());
                context.RegisterCodeFix(action, context.Diagnostics.First());
            }
        }
        internal static void VerifyTypeMethods(ContextReporter context, ITypeSymbol type)
        {
            var methods = type.GetMembers()
                .OfType<IMethodSymbol>()
                .Where(x => x.MethodKind == MethodKind.Ordinary)
                .Where(x => x.DeclaredAccessibility == Accessibility.Public)
                .Where(x => !x.IsStatic)
                .ToArray();

            var alreadyAnalyzed = new HashSet<ITypeSymbol>();
            foreach (var method in methods)
            {
                var methodDecl = method.DeclaringSyntaxReferences[0].GetSyntax() as MethodDeclarationSyntax;
                if (methodDecl == null) return;

                VerifyType(context, methodDecl.ReturnType.GetLocation(), method.ReturnType, alreadyAnalyzed);
                foreach (var item in method.Parameters.Zip(methodDecl.ParameterList.Parameters, (symbol, syntax) => new { symbol, syntax }))
                {
                    VerifyType(context, item.syntax.Type.GetLocation(), item.symbol.Type, alreadyAnalyzed);
                }
            }
        }
        static bool VerifyMember(ContextReporter context, Location reportLocation, ISymbol member, Location typeLocation)
        {
            if (member.Locations[0].Kind == LocationKind.MetadataFile)
            {
                return false; // in metadata, I don't know...
            }

            if (member is IPropertySymbol)
            {
                // get only property
                var prop = member as IPropertySymbol;
                if (prop.SetMethod == null)
                {
                    return false;
                }
            }

            var attr = member.GetAttributes();
            if (attr.Length == 0)
            {
                context.ReportDiagnostic(Diagnostic.Create(SerializeTypeMustBeDataContract, reportLocation, new[] { typeLocation }, member.ContainingType.ToString()));
                return true;
            }

            if (attr.Any(x => x.AttributeClass.ToString() == typeof(System.Runtime.Serialization.IgnoreDataMemberAttribute).FullName))
            {
                return false;
            }

            var dataMemberAttr = attr.FirstOrDefault(y => y.AttributeClass.ToString() == typeof(System.Runtime.Serialization.DataMemberAttribute).FullName);
            if (dataMemberAttr == null)
            {
                context.ReportDiagnostic(Diagnostic.Create(SerializeTypeMustBeDataContract, reportLocation, new[] { typeLocation }, member.ContainingType.ToString()));
                return true;
            }

            var hasOrder = dataMemberAttr.NamedArguments.Any(x => x.Key == "Order");
            if (!hasOrder)
            {
                context.ReportDiagnostic(Diagnostic.Create(SerializeTypeMustBeDataContract, reportLocation, new[] { typeLocation }, member.ContainingType.ToString()));
                return true;
            }

            return false;
        }
        internal static void VerifyType(ContextReporter context, Location reportLocation, ITypeSymbol type, HashSet<ITypeSymbol> alreadyAnalyzed)
        {
            if (type.TypeKind == TypeKind.Array)
            {
                var array = type as IArrayTypeSymbol;
                VerifyType(context, reportLocation, array.ElementType, alreadyAnalyzed);
                return;
            }

            var namedTypeSymbol = (type as INamedTypeSymbol);
            if (namedTypeSymbol != null && namedTypeSymbol.IsGenericType)
            {
                foreach (var item in namedTypeSymbol.TypeArguments)
                {
                    VerifyType(context, reportLocation, item, alreadyAnalyzed);
                }
                return;
            }

            if (type.TypeKind == TypeKind.Class || type.TypeKind == TypeKind.Struct)
            {
                if (type.Locations[0].Kind == LocationKind.MetadataFile)
                {
                    return;
                }

                if (!alreadyAnalyzed.Add(type)) return;

                var typeLocation = type.Locations[0];
                var members = type.GetMembers().Where(x => x is IFieldSymbol || x is IPropertySymbol)
                    .Where(x=> x.CanBeReferencedByName)
                    .ToArray();
                if (members.Length != 0)
                {
                    var hasDiagnostic = false;
                    foreach (var member in members)
                    {
                        if (!hasDiagnostic)
                        {
                            hasDiagnostic = VerifyMember(context, reportLocation, member, typeLocation);
                        }

                        VerifyType(context, reportLocation, (member as IFieldSymbol)?.Type ?? (member as IPropertySymbol)?.Type ?? null, alreadyAnalyzed);
                    }

                    if (!hasDiagnostic)
                    {
                        var dataContract = type.GetAttributes().FirstOrDefault(y => y.AttributeClass.ToString() == "System.Runtime.Serialization.DataContractAttribute");
                        if (dataContract == null)
                        {
                            context.ReportDiagnostic(Diagnostic.Create(SerializeTypeMustBeDataContract, reportLocation, new[] { typeLocation }, type.ToString()));
                        }
                    }
                }
            }
        }