@@ -11,6 +11,8 @@ namespace Flow.Launcher.Localization.Analyzers.Localize
1111 [ DiagnosticAnalyzer ( LanguageNames . CSharp ) ]
1212 public class OldGetTranslateAnalyzer : DiagnosticAnalyzer
1313 {
14+ #region DiagnosticAnalyzer
15+
1416 public override ImmutableArray < DiagnosticDescriptor > SupportedDiagnostics => ImmutableArray . Create (
1517 AnalyzerDiagnostics . OldLocalizationApiUsed
1618 ) ;
@@ -22,29 +24,42 @@ public override void Initialize(AnalysisContext context)
2224 context . RegisterSyntaxNodeAction ( AnalyzeNode , SyntaxKind . InvocationExpression ) ;
2325 }
2426
27+ #endregion
28+
29+ #region Analyze Methods
30+
2531 private static void AnalyzeNode ( SyntaxNodeAnalysisContext context )
2632 {
2733 var invocationExpr = ( InvocationExpressionSyntax ) context . Node ;
2834 var semanticModel = context . SemanticModel ;
2935 var symbolInfo = semanticModel . GetSymbolInfo ( invocationExpr ) ;
3036
37+ // Check if the method is a format string call
3138 if ( ! ( symbolInfo . Symbol is IMethodSymbol methodSymbol ) ) return ;
3239
33- if ( IsFormatStringCall ( methodSymbol ) &&
34- GetFirstArgumentInvocationExpression ( invocationExpr ) is InvocationExpressionSyntax innerInvocationExpr )
40+ // First branch: detect a call to string.Format containing a translate call anywhere in its arguments.
41+ if ( IsFormatStringCall ( methodSymbol ) )
3542 {
36- if ( ! IsTranslateCall ( semanticModel . GetSymbolInfo ( innerInvocationExpr ) ) ||
37- ! ( GetFirstArgumentStringValue ( innerInvocationExpr ) is string translationKey ) )
38- return ;
39-
40- var diagnostic = Diagnostic . Create (
41- AnalyzerDiagnostics . OldLocalizationApiUsed ,
42- invocationExpr . GetLocation ( ) ,
43- translationKey ,
44- GetInvocationArguments ( invocationExpr )
45- ) ;
46- context . ReportDiagnostic ( diagnostic ) ;
43+ var arguments = invocationExpr . ArgumentList . Arguments ;
44+ // Check all arguments is an invocation (i.e. a candidate for Context.API.GetTranslation(…))
45+ for ( int i = 0 ; i < arguments . Count ; i ++ )
46+ {
47+ if ( GetArgumentInvocationExpression ( invocationExpr , i ) is InvocationExpressionSyntax innerInvocationExpr &&
48+ IsTranslateCall ( semanticModel . GetSymbolInfo ( innerInvocationExpr ) ) &&
49+ GetFirstArgumentStringValue ( innerInvocationExpr ) is string translationKey )
50+ {
51+ var diagnostic = Diagnostic . Create (
52+ AnalyzerDiagnostics . OldLocalizationApiUsed ,
53+ invocationExpr . GetLocation ( ) ,
54+ translationKey ,
55+ GetInvocationArguments ( invocationExpr , i )
56+ ) ;
57+ context . ReportDiagnostic ( diagnostic ) ;
58+ return ;
59+ }
60+ }
4761 }
62+ // Second branch: direct translate call (outside of a Format call)
4863 else if ( IsTranslateCall ( methodSymbol ) && GetFirstArgumentStringValue ( invocationExpr ) is string translationKey )
4964 {
5065 if ( IsParentFormatStringCall ( semanticModel , invocationExpr ) ) return ;
@@ -59,27 +74,42 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
5974 }
6075 }
6176
62- private static string GetInvocationArguments ( InvocationExpressionSyntax invocationExpr ) =>
63- string . Join ( ", " , invocationExpr . ArgumentList . Arguments . Skip ( 1 ) ) ;
77+ #region Utils
6478
65- private static bool IsParentFormatStringCall ( SemanticModel semanticModel , SyntaxNode syntaxNode ) =>
66- syntaxNode is InvocationExpressionSyntax invocationExpressionSyntax &&
67- invocationExpressionSyntax . Parent ? . Parent ? . Parent is SyntaxNode parent &&
68- IsFormatStringCall ( semanticModel ? . GetSymbolInfo ( parent ) ) ;
79+ private static string GetInvocationArguments ( InvocationExpressionSyntax invocationExpr , int translateArgIndex ) =>
80+ string . Join ( ", " , invocationExpr . ArgumentList . Arguments . Skip ( translateArgIndex + 1 ) ) ;
6981
70- private static bool IsFormatStringCall ( SymbolInfo ? symbolInfo ) =>
71- symbolInfo is SymbolInfo info && IsFormatStringCall ( info . Symbol as IMethodSymbol ) ;
82+ /// <summary>
83+ /// Walk up the tree to see if we're already inside a Format call
84+ /// </summary>
85+ private static bool IsParentFormatStringCall ( SemanticModel semanticModel , SyntaxNode syntaxNode )
86+ {
87+ var parent = syntaxNode . Parent ;
88+ while ( parent != null )
89+ {
90+ if ( parent is InvocationExpressionSyntax parentInvocation )
91+ {
92+ var symbol = semanticModel . GetSymbolInfo ( parentInvocation ) . Symbol as IMethodSymbol ;
93+ if ( IsFormatStringCall ( symbol ) )
94+ {
95+ return true ;
96+ }
97+ }
98+ parent = parent . Parent ;
99+ }
100+ return false ;
101+ }
72102
73103 private static bool IsFormatStringCall ( IMethodSymbol methodSymbol ) =>
74- methodSymbol ? . Name is Constants . StringFormatMethodName &&
75- methodSymbol . ContainingType . ToDisplayString ( ) is Constants . StringFormatTypeName ;
104+ methodSymbol ? . Name == Constants . StringFormatMethodName &&
105+ methodSymbol . ContainingType . ToDisplayString ( ) == Constants . StringFormatTypeName ;
76106
77- private static InvocationExpressionSyntax GetFirstArgumentInvocationExpression ( InvocationExpressionSyntax invocationExpr ) =>
78- invocationExpr . ArgumentList . Arguments . FirstOrDefault ( ) ? . Expression as InvocationExpressionSyntax ;
107+ private static InvocationExpressionSyntax GetArgumentInvocationExpression ( InvocationExpressionSyntax invocationExpr , int index ) =>
108+ invocationExpr . ArgumentList . Arguments [ index ] . Expression as InvocationExpressionSyntax ;
79109
80110 private static bool IsTranslateCall ( SymbolInfo symbolInfo ) =>
81111 symbolInfo . Symbol is IMethodSymbol innerMethodSymbol &&
82- innerMethodSymbol . Name is Constants . OldLocalizationMethodName &&
112+ innerMethodSymbol . Name == Constants . OldLocalizationMethodName &&
83113 Constants . OldLocalizationClasses . Contains ( innerMethodSymbol . ContainingType . Name ) ;
84114
85115 private static bool IsTranslateCall ( IMethodSymbol methodSymbol ) =>
@@ -92,5 +122,9 @@ private static string GetFirstArgumentStringValue(InvocationExpressionSyntax inv
92122 return syntax . Token . ValueText ;
93123 return null ;
94124 }
125+
126+ #endregion
127+
128+ #endregion
95129 }
96130}
0 commit comments