From 39c2c7118c49a781477a0c4b122c09598029ceee Mon Sep 17 00:00:00 2001 From: Muaaz Mahmud Date: Thu, 2 Apr 2026 13:50:11 -0400 Subject: [PATCH] SPLA-3311: Allow string.Empty for ConstantAttributeAnalyzer --- .../ApiUsage/ConstantAttributeAnalyzer.cs | 16 ++++++++++++---- .../Specs/ConstantAttributeAnalyzer.cs | 7 +++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/D2L.CodeStyle.Analyzers/ApiUsage/ConstantAttributeAnalyzer.cs b/src/D2L.CodeStyle.Analyzers/ApiUsage/ConstantAttributeAnalyzer.cs index 74178f92..5c9beab8 100644 --- a/src/D2L.CodeStyle.Analyzers/ApiUsage/ConstantAttributeAnalyzer.cs +++ b/src/D2L.CodeStyle.Analyzers/ApiUsage/ConstantAttributeAnalyzer.cs @@ -118,8 +118,8 @@ ISymbol constantAttribute return; } - // Argument is a constant value, so do nothing - if( argument.Value.ConstantValue.HasValue ) { + // Argument is a constant value or string.Empty, so do nothing + if( argument.Value.ConstantValue.HasValue || IsStringEmpty( argument.Value ) ) { return; } @@ -157,9 +157,9 @@ INamedTypeSymbol constantAttribute return; } - // Operand is a constant value, so trust it + // Operand is a constant value or string.Empty, so trust it IOperation operand = conversion.Operand; - if( operand.ConstantValue.HasValue ) { + if( operand.ConstantValue.HasValue || IsStringEmpty( operand ) ) { return; } @@ -216,6 +216,14 @@ ISymbol attributeSymbol ); } + private static bool IsStringEmpty( IOperation operation ) { + if( operation is IFieldReferenceOperation fieldRef ) { + return fieldRef.Field.ContainingType.SpecialType == SpecialType.System_String + && fieldRef.Field.Name == "Empty"; + } + return false; + } + private static bool TypeCanBeConstant( SpecialType specialType ) { switch( specialType ) { case SpecialType.System_Enum: diff --git a/tests/D2L.CodeStyle.Analyzers.Test/Specs/ConstantAttributeAnalyzer.cs b/tests/D2L.CodeStyle.Analyzers.Test/Specs/ConstantAttributeAnalyzer.cs index 255ffb53..8f2abac7 100644 --- a/tests/D2L.CodeStyle.Analyzers.Test/Specs/ConstantAttributeAnalyzer.cs +++ b/tests/D2L.CodeStyle.Analyzers.Test/Specs/ConstantAttributeAnalyzer.cs @@ -80,6 +80,7 @@ void Method() { Logger.Error( CONSTANT_MESSAGE ); Logger.Error( "Organization 1 is constant." ); + Logger.Error( string.Empty ); Logger.Error( /* NonConstantPassedToConstantParameter(message) */ string.Format(CONSTANT_MESSAGE, orgId) /**/ ); Logger.Error( /* NonConstantPassedToConstantParameter(message) */ $"Organization {orgId} is not constant." /**/ ); @@ -94,12 +95,14 @@ void Method() { Types.SomeMethodWithConstantParameter( "This is a constant message" ); Types.SomeMethodWithConstantParameter( CONSTANT_STR ); Types.SomeMethodWithConstantParameter( CONSTANT_STR + "This is a constant message" ); + Types.SomeMethodWithConstantParameter( string.Empty ); Types.SomeMethodWithConstantParameter( /* NonConstantPassedToConstantParameter(param1) */ CONSTANT_STR + variableStr /**/ ); Types.SomeMethodWithConstantParameter( /* NonConstantPassedToConstantParameter(param1) */ variableStr /**/ ); Types.SomeMethodWithParameter( "This is a constant message" ); Types.SomeMethodWithParameter( CONSTANT_STR ); Types.SomeMethodWithParameter( CONSTANT_STR + "This is a constant message" ); + Types.SomeMethodWithConstantParameter( string.Empty ); Types.SomeMethodWithParameter( CONSTANT_STR + variableStr ); Types.SomeMethodWithParameter( variableStr ); @@ -212,6 +215,7 @@ string untrusted string variable = "bar"; new Types.ConstantStruct( "abc" ); + new Types.ConstantStruct( string.Empty ); new Types.ConstantStruct( Constants.String ); new Types.ConstantStruct( constant ); new Types.ConstantStruct( trusted ); @@ -219,6 +223,7 @@ string untrusted new Types.ConstantStruct( /* NonConstantPassedToConstantParameter(value) */ untrusted /**/ ); new Types.NonConstantStruct( "abc" ); + new Types.NonConstantStruct( string.Empty ); new Types.NonConstantStruct( Constants.String ); new Types.NonConstantStruct( constant ); new Types.NonConstantStruct( trusted ); @@ -264,6 +269,7 @@ string untrusted string variable = "bar"; { Types.ConstantStruct v = "abc"; } + { Types.ConstantStruct v = string.Empty; } { Types.ConstantStruct v = Constants.String; } { Types.ConstantStruct v = constant; } { Types.ConstantStruct v = trusted; } @@ -271,6 +277,7 @@ string untrusted { Types.ConstantStruct v = /* NonConstantPassedToConstantParameter(value) */ untrusted /**/; } { Types.NonConstantStruct v = "abc"; } + { Types.NonConstantStruct v = string.Empty; } { Types.NonConstantStruct v = Constants.String; } { Types.NonConstantStruct v = constant; } { Types.NonConstantStruct v = trusted; }