@@ -183,27 +183,34 @@ public override AstVisitAction VisitInvokeMemberExpression(InvokeMemberExpressio
183183 {
184184 // Look for [typename]::new(...) and [typename]::$dynamicMethodName syntax
185185
186+ #if PSV7
187+ if ( ! TargetsNonPS7 ( ) )
188+ {
189+ return AstVisitAction . Continue ;
190+ }
191+
192+ if ( methodCallAst . NullConditional )
193+ {
194+ AddDiagnostic (
195+ methodCallAst ,
196+ "null-conditional method invocation" ,
197+ "${x}?.Method()" ,
198+ "3,4,5,6" ) ;
199+ }
200+ #endif
201+
186202 if ( ! _targetVersions . Contains ( s_v3 ) && ! _targetVersions . Contains ( s_v4 ) )
187203 {
188204 return AstVisitAction . Continue ;
189205 }
190206
191207 if ( _targetVersions . Contains ( s_v3 ) && methodCallAst . Member is VariableExpressionAst )
192208 {
193- string message = string . Format (
194- CultureInfo . CurrentCulture ,
195- Strings . UseCompatibleSyntaxError ,
209+ AddDiagnostic (
210+ methodCallAst ,
196211 "dynamic method invocation" ,
197- methodCallAst . Extent . Text ,
212+ "$x.$method()" ,
198213 "3" ) ;
199-
200- _diagnosticAccumulator . Add ( new DiagnosticRecord (
201- message ,
202- methodCallAst . Extent ,
203- _rule . GetName ( ) ,
204- _rule . Severity ,
205- _analyzedFilePath
206- ) ) ;
207214 }
208215
209216 if ( ! ( methodCallAst . Expression is TypeExpressionAst typeExpressionAst ) )
@@ -226,22 +233,7 @@ public override AstVisitAction VisitInvokeMemberExpression(InvokeMemberExpressio
226233 typeName ,
227234 methodCallAst . Arguments ) ;
228235
229- string message = string . Format (
230- CultureInfo . CurrentCulture ,
231- Strings . UseCompatibleSyntaxError ,
232- "constructor" ,
233- methodCallAst . Extent . Text ,
234- "3,4" ) ;
235-
236- _diagnosticAccumulator . Add ( new DiagnosticRecord (
237- message ,
238- methodCallAst . Extent ,
239- _rule . GetName ( ) ,
240- _rule . Severity ,
241- _analyzedFilePath ,
242- ruleId : null ,
243- suggestedCorrections : new [ ] { suggestedCorrection }
244- ) ) ;
236+ AddDiagnostic ( methodCallAst , "constructor" , "[type]::new()" , "3,4" , suggestedCorrection ) ;
245237
246238 return AstVisitAction . Continue ;
247239 }
@@ -263,21 +255,7 @@ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst fun
263255 return AstVisitAction . Continue ;
264256 }
265257
266- string message = string . Format (
267- CultureInfo . CurrentCulture ,
268- Strings . UseCompatibleSyntaxError ,
269- "workflow" ,
270- "workflow { ... }" ,
271- "6" ) ;
272-
273- _diagnosticAccumulator . Add (
274- new DiagnosticRecord (
275- message ,
276- functionDefinitionAst . Extent ,
277- _rule . GetName ( ) ,
278- _rule . Severity ,
279- _analyzedFilePath
280- ) ) ;
258+ AddDiagnostic ( functionDefinitionAst , "workflow" , "workflow { ... }" , "6,7" ) ;
281259
282260 return AstVisitAction . Continue ;
283261 }
@@ -292,22 +270,12 @@ public override AstVisitAction VisitUsingStatement(UsingStatementAst usingStatem
292270 return AstVisitAction . Continue ;
293271 }
294272
295- string message = string . Format (
296- CultureInfo . CurrentCulture ,
297- Strings . UseCompatibleSyntaxError ,
273+ AddDiagnostic (
274+ usingStatementAst ,
298275 "using statement" ,
299276 "using ...;" ,
300277 "3,4" ) ;
301278
302- _diagnosticAccumulator . Add (
303- new DiagnosticRecord (
304- message ,
305- usingStatementAst . Extent ,
306- _rule . GetName ( ) ,
307- _rule . Severity ,
308- _analyzedFilePath
309- ) ) ;
310-
311279 return AstVisitAction . Continue ;
312280 }
313281
@@ -340,6 +308,145 @@ public override AstVisitAction VisitTypeDefinition(TypeDefinitionAst typeDefinit
340308 }
341309#endif
342310
311+ #if PSV7
312+ public override AstVisitAction VisitMemberExpression ( MemberExpressionAst memberExpressionAst )
313+ {
314+ if ( ! TargetsNonPS7 ( ) )
315+ {
316+ return AstVisitAction . Continue ;
317+ }
318+
319+ if ( memberExpressionAst . NullConditional )
320+ {
321+ AddDiagnostic (
322+ memberExpressionAst ,
323+ "null-conditional member access" ,
324+ "${x}?.Member" ,
325+ "3,4,5,6" ) ;
326+ }
327+
328+ return AstVisitAction . Continue ;
329+ }
330+
331+ public override AstVisitAction VisitAssignmentStatement ( AssignmentStatementAst assignmentStatementAst )
332+ {
333+ if ( ! TargetsNonPS7 ( ) )
334+ {
335+ return AstVisitAction . Continue ;
336+ }
337+
338+ if ( assignmentStatementAst . Operator == TokenKind . QuestionQuestionEquals )
339+ {
340+ AddDiagnostic ( assignmentStatementAst , "null-conditional assignment" , "$x ??= $y" , "3,4,5,6" ) ;
341+ }
342+
343+ return AstVisitAction . Continue ;
344+ }
345+
346+ public override AstVisitAction VisitBinaryExpression ( BinaryExpressionAst binaryExpressionAst )
347+ {
348+ if ( ! TargetsNonPS7 ( ) )
349+ {
350+ return AstVisitAction . Continue ;
351+ }
352+
353+ if ( binaryExpressionAst . Operator == TokenKind . QuestionQuestion )
354+ {
355+ AddDiagnostic (
356+ binaryExpressionAst ,
357+ "null-coalescing operator" ,
358+ "$x ?? $y" ,
359+ "3,4,5,6" ) ;
360+ }
361+
362+ return AstVisitAction . Continue ;
363+ }
364+
365+ public override AstVisitAction VisitTernaryExpression ( TernaryExpressionAst ternaryExpressionAst )
366+ {
367+ if ( ! TargetsNonPS7 ( ) )
368+ {
369+ return AstVisitAction . Continue ;
370+ }
371+
372+ var correction = new CorrectionExtent (
373+ ternaryExpressionAst . Extent ,
374+ $ "if ({ ternaryExpressionAst . Condition . Extent . Text } ) {{ { ternaryExpressionAst . IfTrue . Extent . Text } }} else {{ { ternaryExpressionAst . IfFalse . Extent . Text } }}",
375+ _analyzedFilePath ) ;
376+
377+ AddDiagnostic (
378+ ternaryExpressionAst ,
379+ "ternary expression" ,
380+ "<test> ? <exp1> : <exp2>" ,
381+ "3,4,5,6" ,
382+ correction ) ;
383+
384+ return AstVisitAction . Continue ;
385+ }
386+
387+ public override AstVisitAction VisitPipelineChain ( PipelineChainAst statementChain )
388+ {
389+ if ( ! TargetsNonPS7 ( ) )
390+ {
391+ return AstVisitAction . Continue ;
392+ }
393+
394+ AddDiagnostic (
395+ statementChain ,
396+ "pipeline chain" ,
397+ "<pipeline1> && <pipeline2> OR <pipeline1> || <pipeline2>" ,
398+ "3,4,5,6" ) ;
399+
400+ return AstVisitAction . Continue ;
401+ }
402+
403+ private bool TargetsNonPS7 ( )
404+ {
405+ return _targetVersions . Contains ( s_v3 )
406+ || _targetVersions . Contains ( s_v4 )
407+ || _targetVersions . Contains ( s_v5 )
408+ || _targetVersions . Contains ( s_v6 ) ;
409+ }
410+ #endif
411+
412+ private void AddDiagnostic (
413+ Ast offendingAst ,
414+ string syntaxName ,
415+ string syntaxExample ,
416+ string unsupportedVersions ,
417+ CorrectionExtent correction = null )
418+ {
419+ string message = string . Format (
420+ CultureInfo . CurrentCulture ,
421+ Strings . UseCompatibleSyntaxError ,
422+ syntaxName ,
423+ syntaxExample ,
424+ unsupportedVersions ) ;
425+
426+ if ( correction == null )
427+ {
428+ _diagnosticAccumulator . Add (
429+ new DiagnosticRecord (
430+ message ,
431+ offendingAst . Extent ,
432+ _rule . GetName ( ) ,
433+ _rule . Severity ,
434+ _analyzedFilePath ) ) ;
435+
436+ return ;
437+ }
438+
439+ _diagnosticAccumulator . Add (
440+ new DiagnosticRecord (
441+ message ,
442+ offendingAst . Extent ,
443+ _rule . GetName ( ) ,
444+ _rule . Severity ,
445+ _analyzedFilePath ,
446+ ruleId : null ,
447+ new [ ] { correction } ) ) ;
448+ }
449+
343450 private static CorrectionExtent CreateNewObjectCorrection (
344451 string filePath ,
345452 IScriptExtent offendingExtent ,
0 commit comments