Skip to content

Commit

Permalink
Move ArgumentList impl to extension mehtods in the language projects
Browse files Browse the repository at this point in the history
  • Loading branch information
martin-strecker-sonarsource committed Oct 23, 2023
1 parent 81a6001 commit 373274e
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,18 @@ public static bool IsParentKind<T>(this SyntaxNode node, SyntaxKind kind, out T
return false;
}

public static IReadOnlyList<ArgumentSyntax> ArgumentList(this SyntaxNode node) =>
(node switch
{
ObjectCreationExpressionSyntax creation => creation.ArgumentList,
InvocationExpressionSyntax invocation => invocation.ArgumentList,
ConstructorInitializerSyntax constructorInitializer => constructorInitializer.ArgumentList,
null => null,
_ when PrimaryConstructorBaseTypeSyntaxWrapper.IsInstance(node) => ((PrimaryConstructorBaseTypeSyntaxWrapper)node).ArgumentList,
_ when ImplicitObjectCreationExpressionSyntaxWrapper.IsInstance(node) => ((ImplicitObjectCreationExpressionSyntaxWrapper)node).ArgumentList,
_ => throw new InvalidOperationException($"The {nameof(node)} of kind {node.Kind()} does not have an {nameof(ArgumentList)}."),
})?.Arguments ?? (IReadOnlyList<ArgumentSyntax>)Array.Empty<ArgumentSyntax>();

/// <summary>
/// Returns the left hand side of a conditional access expression. Returns c in case like a?.b?[0].c?.d.e?.f if d is passed.
/// </summary>
Expand Down
12 changes: 2 additions & 10 deletions analyzers/src/SonarAnalyzer.CSharp/Facade/CSharpSyntaxFacade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,8 @@ public override IEnumerable<SyntaxNode> ArgumentExpressions(SyntaxNode node) =>
ArgumentList(node)?.OfType<ArgumentSyntax>().Select(x => x.Expression) ?? Enumerable.Empty<SyntaxNode>();

public override IReadOnlyList<SyntaxNode> ArgumentList(SyntaxNode node) =>
(node switch
{
ObjectCreationExpressionSyntax creation => creation.ArgumentList,
InvocationExpressionSyntax invocation => invocation.ArgumentList,
ConstructorInitializerSyntax constructorInitializer => constructorInitializer.ArgumentList,
null => null,
_ when PrimaryConstructorBaseTypeSyntaxWrapper.IsInstance(node) => ((PrimaryConstructorBaseTypeSyntaxWrapper)node).ArgumentList,
_ when ImplicitObjectCreationExpressionSyntaxWrapper.IsInstance(node) => ((ImplicitObjectCreationExpressionSyntaxWrapper)node).ArgumentList,
_ => throw InvalidOperation(node, nameof(ArgumentExpressions))
})?.Arguments ?? (IReadOnlyList<SyntaxNode>)Array.Empty<SyntaxNode>();
node.ArgumentList();

public override SyntaxToken? ArgumentNameColon(SyntaxNode argument) =>
(argument as ArgumentSyntax)?.NameColon?.Name?.Identifier;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,7 @@ public override IEnumerable<SyntaxNode> ArgumentExpressions(SyntaxNode node) =>
ArgumentList(node).OfType<ArgumentSyntax>().Select(x => x.GetExpression()).WhereNotNull();

public override IReadOnlyList<SyntaxNode> ArgumentList(SyntaxNode node) =>
(node switch
{
ObjectCreationExpressionSyntax creation => creation.ArgumentList,
InvocationExpressionSyntax invocation => invocation.ArgumentList,
null => null,
_ => throw InvalidOperation(node, nameof(ArgumentExpressions))
})?.Arguments ?? (IReadOnlyList<SyntaxNode>)Array.Empty<SyntaxNode>();
node.ArgumentList();

public override int? ArgumentIndex(SyntaxNode argument) =>
Cast<ArgumentSyntax>(argument).GetArgumentIndex();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,21 @@ public static ExpressionSyntax Get(this ArgumentListSyntax argumentList, int ind
? argumentList.Arguments[index].GetExpression().RemoveParentheses()
: null;

public static IReadOnlyList<ArgumentSyntax> ArgumentList(this SyntaxNode node) =>
(node switch
{
ObjectCreationExpressionSyntax creation => creation.ArgumentList,
InvocationExpressionSyntax invocation => invocation.ArgumentList,
ModifiedIdentifierSyntax modified => modified.ArrayBounds,
AttributeSyntax attribute => attribute.ArgumentList,
MidExpressionSyntax mid => mid.ArgumentList,
RaiseEventStatementSyntax raise => raise.ArgumentList,
RedimClauseSyntax reDim => reDim.ArrayBounds,
ArrayCreationExpressionSyntax arrayCreation => arrayCreation.ArrayBounds,
null => null,
_ => throw new InvalidOperationException($"The {nameof(node)} of kind {node.Kind()} does not have an {nameof(ArgumentList)}."),
})?.Arguments ?? (IReadOnlyList<ArgumentSyntax>)Array.Empty<ArgumentSyntax>();

/// <summary>
/// Returns argument expressions for given parameter.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,92 @@ public void GetMappedFilePath(string code, string expectedFileName = DefaultFile
syntaxTree.GetRoot().GetMappedFilePathFromRoot().Should().Be(expectedFileName);
}

[DataTestMethod]
[DataRow("$$M(1)$$;")]
[DataRow("_ = $$new C(1)$$;")]
[DataRow("C c = $$new(1)$$;")]
public void ArgumentList_InvocationObjectCreation(string statement)
{
var code = $$"""
public class C(int p) {
public void M(int p) {
{{statement}}
}
}
""";
var node = NodeBetweenMarkers(code, LanguageNames.CSharp);
var argumentList = ExtensionsCS.ArgumentList(node);
var argument = argumentList.Should().ContainSingle().Which;
(argument is { Expression: SyntaxCS.LiteralExpressionSyntax { Token.ValueText: "1" } }).Should().BeTrue();
}

[DataTestMethod]
[DataRow("base")]
[DataRow("this")]
public void ArgumentList_ConstructorInitializer(string keyword)
{
var code = $$"""
public class Base(int p);

public class C: Base
{
public C(): $${{keyword}}(1)$$ { }
public C(int p): base(p) { }
}

""";
var node = NodeBetweenMarkers(code, LanguageNames.CSharp);
var argumentList = ExtensionsCS.ArgumentList(node);
var argument = argumentList.Should().ContainSingle().Which;
(argument is { Expression: SyntaxCS.LiteralExpressionSyntax { Token.ValueText: "1" } }).Should().BeTrue();
}

[TestMethod]
public void ArgumentList_PrimaryConstructorBaseType()
{
var code = """
public class Base(int p);
public class Derived(int p): $$Base(1)$$;
""";
var node = NodeBetweenMarkers(code, LanguageNames.CSharp);
var argumentList = ExtensionsCS.ArgumentList(node);
var argument = argumentList.Should().ContainSingle().Which;
(argument is { Expression: SyntaxCS.LiteralExpressionSyntax { Token.ValueText: "1" } }).Should().BeTrue();
}

[DataTestMethod]
[DataRow("_ = $$new System.Collections.Generic.List<int> { 0 }$$;")]
public void ArgumentList_NoList(string statement)
{
var code = $$"""
public class C {
public void M() {
{{statement}}
}
}
""";
var node = NodeBetweenMarkers(code, LanguageNames.CSharp);
var argumentList = ExtensionsCS.ArgumentList(node);
argumentList.Should().BeEmpty();
}

[DataTestMethod]
[DataRow("_ = $$new int[] { 1 }$$;")]
[DataRow("_ = $$new { A = 1 }$$;")]
public void ArgumentList_UnsupportedNodeKinds(string statement)
{
var code = $$"""
public class C {
public void M() {
{{statement}}
}
}
""";
var node = NodeBetweenMarkers(code, LanguageNames.CSharp);
var sut = () => ExtensionsCS.ArgumentList(node);
sut.Should().Throw<InvalidOperationException>();
}

private static SyntaxNode NodeBetweenMarkers(string code, string language)
{
var position = code.IndexOf("$$");
Expand Down

0 comments on commit 373274e

Please sign in to comment.