public void Execute( GeneratorExecutionContext context) { LaunchDebugger(context); if (context.SyntaxReceiver is not SyntaxReceiver receiver) { return; } var knownTypes = new KnownTypes(context.Compilation); var candidateTypes = new List <SourceTypeInfo>(); foreach (var candidateSyntax in receiver.CandidateSyntaxes) { var sourceTypeInfo = SourceTypeInfo.TryCreate( context, candidateSyntax, knownTypes, this._options, out var diagnostics); context.ReportDiagnostics(diagnostics); if (sourceTypeInfo is null) { continue; } candidateTypes.Add(sourceTypeInfo); } var typeMap = candidateTypes.ToDictionary( x => x.TypeSymbol, (IEqualityComparer <ITypeSymbol>)SymbolEqualityComparer.Default); foreach (var candidateType in candidateTypes.ToArray()) { if (!candidateType.HasComparableAttribute) { continue; } var options = candidateType.GenerateOptions; foreach (var member in candidateType.Members) { if (options.GenerateGenericComparable || options.GenerateNonGenericComparable || options.GenerateOperators || options.GenerateStructuralComparable) { var memberType = member.Type; if (knownTypes.IsGenericComparable(memberType)) { continue; } if (knownTypes.IsNonGenericComparable(memberType)) { continue; } if (knownTypes.IsStructuralComparable(memberType)) { continue; } if (typeMap.TryGetValue(memberType, out var targetType) && targetType.HasComparableAttribute) { continue; } if (!knownTypes.TryGetNullableUnderlyingType(memberType, out var underlyingType)) { continue; } if (typeMap.TryGetValue(underlyingType, out var targetType2) && targetType2.HasComparableAttribute) { continue; } var memberLocation = member.Symbol.DeclaringSyntaxReferences .Select(x => Location.Create(x.SyntaxTree, x.Span)) .ToArray(); context.ReportDiagnostic( DiagnosticFactory.MemberIsNotComparable( candidateType.FullName, member.Name, member.TypeName, memberLocation[0], memberLocation.Skip(1))); } } } foreach (var sourceType in candidateTypes) { var options = sourceType.GenerateOptions; string fullName = sourceType.FullName; GenerateCode( context, new CommonGenerator(sourceType), $"{fullName}_Common.cs"); if (options.GenerateEqualityContract && !sourceType.HasEqualityContract && !sourceType.IsValueType) { GenerateCode( context, new EqualityContractGenerator(sourceType), $"{fullName}_EqualityContract.cs"); } if (options.GenerateEquatable && !sourceType.IsEquatable) { GenerateCode( context, new EquatableGenerator(sourceType), $"{fullName}_Equatable.cs"); } if (options.GenerateGenericComparable && !sourceType.IsGenericComparable) { GenerateCode( context, new GenericComparableGenerator(sourceType), $"{fullName}_GenericComparable.cs"); } if (options.GenerateNonGenericComparable && !sourceType.IsNonGenericComparable) { GenerateCode( context, new NonGenericComparableGenerator(sourceType), $"{fullName}_NonGenericComparable.cs"); } if (options.OverrideObjectMethods) { if (!sourceType.OverridesObjectEquals) { GenerateCode( context, new ObjectEqualsGenerator(sourceType), $"{fullName}_ObjectEquals.cs"); } if (!sourceType.OverridesObjectGetHashCode) { GenerateCode( context, new ObjectGetHashCodeGenerator(sourceType), $"{fullName}_ObjectGetHashCode.cs"); } } if (options.GenerateOperators && !sourceType.DefinedNullableParameterOperator) { GenerateCode( context, new EqualityOperatorsGenerator(sourceType), $"{fullName}_EqualityOperators.cs"); if (sourceType.HasComparableAttribute) { GenerateCode( context, new ComparisonOperatorsGenerator(sourceType), $"{fullName}_ComparisonOperators.cs"); } } } }
public BaseTypeInfo( INamedTypeSymbol typeSymbol, KnownTypes knownTypes) { if (typeSymbol is null) { throw new ArgumentNullException(nameof(typeSymbol)); } if (knownTypes is null) { throw new ArgumentNullException(nameof(knownTypes)); } var comparer = SymbolEqualityComparer.Default; this.TypeSymbol = typeSymbol; this.FullName = typeSymbol.GetFullName(); this.IsEquatable = knownTypes.IsEquatable(typeSymbol); this.IsGenericComparable = knownTypes.IsGenericComparable(typeSymbol); this.IsNonGenericComparable = knownTypes.IsNonGenericComparable(typeSymbol); this.IsStructuralEquatable = knownTypes.IsStructuralEquatable(typeSymbol); this.IsStructuralComparable = knownTypes.IsStructuralComparable(typeSymbol); var objectEquals = knownTypes.Object.GetMembers(nameof(object.Equals)) .OfType <IMethodSymbol>() .Single(x => x.Parameters.Length == 1 && comparer.Equals(x.Parameters[0].Type, knownTypes.Object)); var objectEqualsOverride = typeSymbol.GetOverrideSymbol(objectEquals !, comparer); this.OverridesObjectEquals = objectEqualsOverride is not null; var objectGetHashCode = knownTypes.Object.GetMembers(nameof(object.GetHashCode)) .OfType <IMethodSymbol>() .Single(x => x.Parameters.Length == 0); var objectGetHashCodeOverride = typeSymbol.GetOverrideSymbol(objectGetHashCode !, comparer); this.OverridesObjectGetHashCode = objectGetHashCodeOverride is not null; var operators = typeSymbol.GetMembers() .OfType <IMethodSymbol>() .Where(x => x.MethodKind == MethodKind.UserDefinedOperator && x.Parameters.Length == 2); var nullableType = typeSymbol; if (typeSymbol.IsValueType) { nullableType = knownTypes.MakeNullable(typeSymbol); } var operatorNames = new[] { "op_Equality", "op_Inequality", "op_LessThan", "op_GreaterThan", "op_LessThanOrEqual", "op_GreaterThanOrEqual" }; foreach (var op in operators) { if (!operatorNames.Contains(op.Name, StringComparer.Ordinal)) { continue; } var type1 = op.Parameters[0].Type; var type2 = op.Parameters[1].Type; if (!this.DefinedNullableParameterOperator) { bool matchTypes = comparer.Equals(type1, nullableType) && comparer.Equals(type2, nullableType); this.DefinedNullableParameterOperator = matchTypes; } if (typeSymbol.IsValueType && !this.DefinedNonNullableParameterOperator) { bool matchTypes = comparer.Equals(type1, typeSymbol) && comparer.Equals(type2, typeSymbol); this.DefinedNonNullableParameterOperator = matchTypes; } } bool hasEqualityContract = typeSymbol.GetMembers("EqualityContract") .OfType <IPropertySymbol>() .Any(x => x.IsVirtual && comparer.Equals(x.Type, knownTypes.Type)); this.HasEqualityContract = hasEqualityContract; }