Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public class ServicesAnalyzer : DiagnosticAnalyzer
Diagnostics.Srv.TypeInBeamGeneratedIsMissingBeamGeneratedAttribute, Diagnostics.Srv.DictionaryKeyMustBeStringOnSerializableTypes,
Diagnostics.Srv.FieldOnSerializableTypeIsSubtypeFromDictionary, Diagnostics.Srv.FieldOnSerializableTypeIsSubtypeFromList,
Diagnostics.Srv.CallableMethodDeclarationTypeIsInvalidDictionary, Diagnostics.Srv.CallableMethodDeclarationTypeIsSubtypeFromDictionary,
Diagnostics.Srv.CallableMethodDeclarationTypeIsSubtypeFromList, Diagnostics.Srv.InvalidGenericTypeOnMicroservice);
Diagnostics.Srv.CallableMethodDeclarationTypeIsSubtypeFromList, Diagnostics.Srv.InvalidGenericTypeOnMicroservice, Diagnostics.Srv.MissingSerializableAttributeForArgument);

public override void Initialize(AnalysisContext context)
{
Expand Down Expand Up @@ -497,7 +497,7 @@ private static void ValidateParameters(SyntaxNodeAnalysisContext context, IMetho
}

ValidateNestedType(context.Compilation, context.ReportDiagnostic, parameterLocation, parameterSymbol.Type, methodSymbol.Name);
ValidateSerializableAttributeOnSymbol(context.Compilation, context.ReportDiagnostic, parameterSymbol.Type, parameterLocation);
ValidateSerializableAttributeOnSymbol(context.Compilation, context.ReportDiagnostic, parameterSymbol.Type, parameterLocation, parameterName: parameterSymbol.Name);
ValidateMembersInSymbol(context.Compilation, context.ReportDiagnostic, parameterSymbol.Type, isBlueprintCompatible, fallbackLocation: parameterLocation);
ValidateContentObjectType(context.ReportDiagnostic, parameterSymbol.Type, parameterLocation, $"parameter {parameterSymbol.Name}");

Expand Down Expand Up @@ -582,7 +582,7 @@ private static void ValidateIfTypeIsInMicroservice(SyntaxNodeAnalysisContext con
}

private static void ValidateSerializableAttributeOnSymbol(Compilation compilation, Action<Diagnostic> reportDiagnostic,
ITypeSymbol typeSymbol, Location fallbackLocation = null, HashSet<string> processedTypes = null)
ITypeSymbol typeSymbol, Location fallbackLocation = null, HashSet<string> processedTypes = null, string parameterName = null)
{
processedTypes ??= new HashSet<string>();

Expand Down Expand Up @@ -637,9 +637,18 @@ private static void ValidateSerializableAttributeOnSymbol(Compilation compilatio
return;
}

Diagnostic diagnostic;

// Try to get type location, if not found because it is out of scope, try to get the fallback.
// If none fallback is passed, use Location.None so we don't throw any Exception.
var diagnostic = Diagnostic.Create(Diagnostics.Srv.MissingSerializableAttributeOnType, location, typeSymbol.Name);
if (!string.IsNullOrWhiteSpace(parameterName))
{
diagnostic = Diagnostic.Create(Diagnostics.Srv.MissingSerializableAttributeForArgument, location, typeSymbol.Name, parameterName);
}
else
{
diagnostic = Diagnostic.Create(Diagnostics.Srv.MissingSerializableAttributeOnType, location, typeSymbol.Name);
}
Comment on lines +644 to +651
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both branches of this 'if' statement write to the same variable - consider using '?' to express intent better.

Copilot uses AI. Check for mistakes.
reportDiagnostic.Invoke(diagnostic);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,15 @@ public static readonly DiagnosticDescriptor MissingSerializableAttributeOnType
helpLinkUri: DocsPageHelper.GetCliDocsPageUrl($"{TROUBLESHOOTING_GUIDE_BASE_URL}#missing-serializable-attribute-on-type", Constants.CLI_CURRENT_DOCS_VERSION),
isEnabledByDefault: true);

public static readonly DiagnosticDescriptor MissingSerializableAttributeForArgument
= new(MISSING_SERIALIZABLE_ATTRIBUTE_ON_TYPE_ID,
Comment on lines +146 to +147
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new diagnostic descriptor MissingSerializableAttributeForArgument is reusing the same diagnostic ID MISSING_SERIALIZABLE_ATTRIBUTE_ON_TYPE_ID as MissingSerializableAttributeOnType. This is problematic because diagnostic IDs should be unique to allow proper identification and filtering of specific diagnostic types. When two diagnostics share the same ID, it becomes impossible to distinguish between them programmatically, which can cause issues with diagnostic suppression, IDE filtering, and diagnostic tracking.

Consider creating a new unique diagnostic ID constant (e.g., MISSING_SERIALIZABLE_ATTRIBUTE_FOR_ARGUMENT_ID = "BEAM_SRV_0024") and using it for this diagnostic descriptor instead of reusing the existing ID.

Copilot uses AI. Check for mistakes.
"Argument type is not serializable",
$"Type of argument '{{1}}' must be serializable or have [BeamGenerateSchema] attribute. Either add the [Serializable] attribute to type '{{0}}' or use different type.",
Category_Services,
DiagnosticSeverity.Error,
helpLinkUri: DocsPageHelper.GetCliDocsPageUrl($"{TROUBLESHOOTING_GUIDE_BASE_URL}#missing-serializable-attribute-on-type", Constants.CLI_CURRENT_DOCS_VERSION),
isEnabledByDefault: true);

public static readonly DiagnosticDescriptor PropertiesFoundInSerializableTypes
= new(PROPERTIES_FOUND_IN_SERIALIZABLE_TYPES_ID,
$"Properties in serializable types are ignored by the client code generator",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,11 @@ public NonSerializableEnum CallServiceEnum()
{
return NonSerializableEnum.None;
}

[ClientCallable]
public void CallWithWrongArgument(object {|#3:wrongArgument|})
{
}
}

public struct {|#0:DTO_AsyncTest|}
Expand Down Expand Up @@ -482,6 +487,10 @@ public enum OtherNonSerializableEnum {
new DiagnosticResult(Diagnostics.Srv.MissingSerializableAttributeOnType)
.WithLocation(2)
.WithArguments("DTO_BeamGenSchemaAttribute"));
ctx.ExpectedDiagnostics.Add(
new DiagnosticResult(Diagnostics.Srv.MissingSerializableAttributeForArgument)
.WithLocation(3)
.WithArguments("Object", "wrongArgument"));

PrepareForRun(ctx, UserCode);

Expand Down
Loading