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); }
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())); } } } } }