Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New rule S6934: You should specify the RouteAttribute when an HttpMethodAttribute is specified at an action level #8954

Merged
merged 21 commits into from
Mar 22, 2024

Conversation

martin-strecker-sonarsource
Copy link
Contributor

@martin-strecker-sonarsource martin-strecker-sonarsource commented Mar 18, 2024

Fixes #8872

Remaining:

@costin-zaharia-sonarsource costin-zaharia-sonarsource force-pushed the Martin/New_S6934 branch 4 times, most recently from 1951a32 to cf8f8bd Compare March 21, 2024 09:15
using Microsoft.AspNetCore.Mvc.Routing;

public partial class HomeController : Controller
{
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a non-compliant action here. I'm not sure if secondary locations are filtered or not. I'm also not sure if reporting a secondary location in a generated file is a problem or not. But it would be interesting to learn.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. These are not filtered.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will not change the behavior, I will just document it.

Copy link
Contributor

@antonioaversa antonioaversa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am almost done with the review. I am releasing a bunch of comments, so that they can be addressed while I finish the review. The rule looks very good.

@antonioaversa
Copy link
Contributor

@costin-zaharia-sonarsource Coverage is almost 100%. I think we should be able to cover if (declaration.GetIdentifier() is { } identifier), maybe with incomplete code having a method missing its name.

@costin-zaharia-sonarsource
Copy link
Member

Coverage is almost 100%. I think we should be able to cover if (declaration.GetIdentifier() is { } identifier), maybe with incomplete code having a method missing its name.

I have mixed feelings about this. Do you see a specific risk that we take if we don't cover this case?

Copy link
Contributor

@antonioaversa antonioaversa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!
I have left a few comments, but those are mostly on tests, and there is no need for another round of review. Once addressed or replied to, the PR can be merged.

}

private static bool CanBeIgnored(string template) =>
string.IsNullOrWhiteSpace(template)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor concern. I have tried the following out:

public class SomeController : Controller
{
    [Route(" ")]
    public IActionResult WithRouteAttribute() => View();
}

It registers the route https://localhost:7010/%20. The same happens with [Route("/t")]
So technically, the rule would apply for any non-null template, including space, tabs, and probably other whitespace.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I've changed the behavior.


using MA = Microsoft.AspNetCore;

public class RouteTemplateIsNotSpecifiedController : Controller
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't seem to have tests for:

  • routes with whitespace chars: space and tab in particular
  • multiple attributes on the same action
    • one attribute with a non-empty route template and one without (non-compliant)
    • both attributes without non-empty route templates (compliant)
    • both attributes with non-empty route templates (non-compliant)
    • mix of HttpMethodAttribute and RouteAttribute

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have already some test cases with a mix:
image
I'll check and add the others


public class RouteTemplateIsNotSpecifiedController : Controller
{
public IActionResult Index() => View(); // Compliant
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personal opinion: I would use the name of the method to convey the meaning for the test. For example:

  • Index -> WithoutHttpAttribute
  • Index2 -> WithHttpAttributeNoRoute
  • Index3 -> WithHttpAttributeAndArgumentListNoRoute
  • etc.

This way the intent for the test becomes clearer, and the list is also easy to rearrange, since the increasing numbering doesn't have to be honored.

public IActionResult AbsoluteUri2(string sortBy) => View(); // Compliant, absolute uri

public IActionResult Error() => View(); // Compliant
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add the following, to document that the "null or whitespace" behavior also applies to Route:

    [Route(" ")]
    public IActionResult WithSpaceRouteInRouteAttribute() => View();  // Compliant

    [Route("\t")]
    public IActionResult WithTabRouteInRouteAttribute() => View();  // Compliant

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made them noncompliant, according to: #8954 (comment)

]);

[TestMethod]
public void SpecifyRouteAttribute_CS() =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test should have the _CSharp12 suffix, instead of _CS.

Copy link

sonarcloud bot commented Mar 22, 2024

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
No data about Duplication

See analysis details on SonarCloud

Copy link

sonarcloud bot commented Mar 22, 2024

@costin-zaharia-sonarsource costin-zaharia-sonarsource merged commit 2d909a7 into master Mar 22, 2024
25 checks passed
@costin-zaharia-sonarsource costin-zaharia-sonarsource deleted the Martin/New_S6934 branch March 22, 2024 13:49
@antonioaversa
Copy link
Contributor

Coverage is almost 100%. I think we should be able to cover if (declaration.GetIdentifier() is { } identifier), maybe with incomplete code having a method missing its name.

I have mixed feelings about this. Do you see a specific risk that we take if we don't cover this case?

I missed this question. I think it's fine. I tried to do something like the following:

class X {
	virtual void (string x) { }
}

But I got an IncompleteMemberSyntax, not a MethodDeclarationSyntax:
image

You can have a missing identifier in a DestructorDeclarationSyntax:

class X {
	~() { }
}

image

However, DestructorDeclarationSyntax derives from BaseMethodDeclarationSyntax, not from MethodDeclarationSyntax.
Similar reasoning applies to all other production rules of base_method_declaration.

Moreover, the identifier is not optional in the production rule of method_declaration.

So I don't see an easy way of generating a case where the Identifier is null.
That means that, in principle, we could use declaration.GetIdentifier() is var identifier, but being defensive is also OK in this case, I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants