Skip to content

Commit e27fb2b

Browse files
committed
fix: Unary Postfix Operations require whitespace skips
1 parent ac68598 commit e27fb2b

File tree

1 file changed

+65
-29
lines changed

1 file changed

+65
-29
lines changed

Rules/UseConsistentWhitespace.cs

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -569,14 +569,14 @@ private IEnumerable<DiagnosticRecord> FindParameterViolations(Ast ast)
569569
bool isInsideString = false;
570570
foreach (var stringAst in stringAsts)
571571
{
572-
if (stringAst.Extent.StartOffset < leftExtent.EndOffset &&
572+
if (stringAst.Extent.StartOffset < leftExtent.EndOffset &&
573573
stringAst.Extent.EndOffset > rightExtent.StartOffset)
574574
{
575575
isInsideString = true;
576576
break;
577577
}
578578
}
579-
579+
580580
if (isInsideString)
581581
{
582582
continue;
@@ -633,7 +633,7 @@ private IEnumerable<DiagnosticRecord> FindSeparatorViolations(TokenOperations to
633633
{
634634
var prevTok = tokenNode.Previous.Value;
635635
var nextTok = tokenNode.Next.Value;
636-
636+
637637
// Skip if comma appears to be within a parameter value (no spaces around it)
638638
if ((prevTok.Kind == TokenKind.Identifier || prevTok.Kind == TokenKind.Generic) &&
639639
(nextTok.Kind == TokenKind.Identifier || nextTok.Kind == TokenKind.Generic) &&
@@ -766,53 +766,49 @@ private IEnumerable<DiagnosticRecord> FindOperatorViolations(TokenOperations tok
766766
continue;
767767
}
768768

769-
if (tokenNode.Previous == null || tokenNode.Next == null || token.Kind == TokenKind.DotDot)
769+
var skipNullOrDotDot = tokenNode.Previous == null ||
770+
tokenNode.Next == null ||
771+
token.Kind == TokenKind.DotDot;
772+
773+
if (skipNullOrDotDot)
770774
{
771775
continue;
772776
}
773777

774-
// Check unary operator handling
775-
bool isUnaryInMethodCall = false;
776-
if (TokenTraits.HasTrait(token.Kind, TokenFlags.UnaryOperator))
778+
// Exclude assignment operator inside of multi-line hash tables if requested
779+
if (IgnoreAssignmentOperatorInsideHashTable && tokenNode.Value.Kind == TokenKind.Equals)
777780
{
778-
// Only skip if it's a unary operator in a method call like $foo.bar(-$var)
779-
if (tokenNode.Previous.Value.Kind == TokenKind.LParen &&
780-
tokenNode.Next.Value.Kind == TokenKind.Variable &&
781-
tokenNode.Previous.Previous != null)
781+
Ast containingAst = tokenOperations.GetAstPosition(tokenNode.Value);
782+
if (containingAst is HashtableAst && containingAst.Extent.EndLineNumber != containingAst.Extent.StartLineNumber)
782783
{
783-
var beforeLParen = tokenNode.Previous.Previous.Value;
784-
isUnaryInMethodCall = beforeLParen.Kind == TokenKind.Dot ||
785-
(beforeLParen.TokenFlags & TokenFlags.MemberName) == TokenFlags.MemberName;
784+
continue;
786785
}
787786
}
788787

789-
if (isUnaryInMethodCall)
790-
{
791-
continue;
792-
}
788+
var isUnaryOperator = TokenTraits.HasTrait(token.Kind, TokenFlags.UnaryOperator);
793789

794-
// exclude assignment operator inside of multi-line hash tables if requested
795-
if (IgnoreAssignmentOperatorInsideHashTable && tokenNode.Value.Kind == TokenKind.Equals)
790+
// Check if we can skip Unary Method invocations or Unary Postfix invocations
791+
// E.g., someObject.method(-$variable) or $A++, $B++
792+
if (isUnaryOperator)
796793
{
797-
Ast containingAst = tokenOperations.GetAstPosition(tokenNode.Value);
798-
if (containingAst is HashtableAst && containingAst.Extent.EndLineNumber != containingAst.Extent.StartLineNumber)
794+
if (IsUnaryOperatorInMethodCall(tokenNode) || IsUnaryPostfixOperator(tokenNode))
799795
{
800796
continue;
801797
}
802798
}
803799

804-
// Check whitespace
800+
// Check for 'before' and 'after' whitespaces
805801
var hasWhitespaceBefore = IsPreviousTokenOnSameLineAndApartByWhitespace(tokenNode);
806-
var hasWhitespaceAfter = tokenNode.Next.Value.Kind == TokenKind.NewLine ||
807-
IsPreviousTokenOnSameLineAndApartByWhitespace(tokenNode.Next);
808802

809-
// Special case: Don't require space before unary operator if preceded by LParen
810-
if (TokenTraits.HasTrait(token.Kind, TokenFlags.UnaryOperator) &&
811-
tokenNode.Previous.Value.Kind == TokenKind.LParen)
803+
if (!hasWhitespaceBefore && isUnaryOperator)
812804
{
813-
hasWhitespaceBefore = true;
805+
// Special case: Don't require space before unary operator if preceded by LParen
806+
hasWhitespaceBefore = IsPreviousTokenLParen(tokenNode);
814807
}
815808

809+
var hasWhitespaceAfter = tokenNode.Next.Value.Kind == TokenKind.NewLine ||
810+
IsPreviousTokenOnSameLineAndApartByWhitespace(tokenNode.Next);
811+
816812
if (!hasWhitespaceAfter || !hasWhitespaceBefore)
817813
{
818814
yield return new DiagnosticRecord(
@@ -832,6 +828,46 @@ private IEnumerable<DiagnosticRecord> FindOperatorViolations(TokenOperations tok
832828
}
833829
}
834830

831+
private bool IsUnaryOperatorInMethodCall(LinkedListNode<Token> tokenNode)
832+
{
833+
var prevToken = tokenNode.Previous;
834+
835+
if (prevToken == null || prevToken.Previous == null)
836+
{
837+
return false;
838+
}
839+
840+
if (!IsPreviousTokenLParen(tokenNode) || tokenNode.Next?.Value.Kind != TokenKind.Variable)
841+
{
842+
return false;
843+
}
844+
845+
var tokenBeforeLParam = prevToken.Previous.Value;
846+
847+
// Pattern: someObject.method(-$variable)
848+
return tokenBeforeLParam.Kind == TokenKind.Dot ||
849+
(tokenBeforeLParam.TokenFlags & TokenFlags.MemberName) == TokenFlags.MemberName;
850+
}
851+
852+
private bool IsUnaryPostfixOperator(LinkedListNode<Token> tokenNode)
853+
{
854+
var token = tokenNode.Value;
855+
856+
if (token.Kind != TokenKind.PlusPlus && token.Kind != TokenKind.MinusMinus)
857+
{
858+
return false;
859+
}
860+
861+
// Postfix operators come after variables, identifiers, or closing brackets/parentheses
862+
var prevToken = tokenNode.Previous.Value;
863+
864+
return prevToken.Kind == TokenKind.Variable ||
865+
prevToken.Kind == TokenKind.Identifier ||
866+
prevToken.Kind == TokenKind.RBracket || // for array access like $arr[0]++
867+
prevToken.Kind == TokenKind.RParen || // for expressions like ($x)++
868+
(prevToken.TokenFlags & TokenFlags.MemberName) == TokenFlags.MemberName;
869+
}
870+
835871
private List<CorrectionExtent> GetCorrections(
836872
Token prevToken,
837873
Token token,

0 commit comments

Comments
 (0)