Skip to content

Conversation

@ZiadMarey
Copy link
Contributor

No description provided.

@hashicorp-vault-sonar-prod
Copy link

hashicorp-vault-sonar-prod bot commented Dec 23, 2025

SONARPHP-1721

@ZiadMarey ZiadMarey requested a review from petertrr December 23, 2025 14:28
Copy link

@felix-pauck-sonarsource felix-pauck-sonarsource left a comment

Choose a reason for hiding this comment

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

Works well 🙂.

I think the code can be improved in parts, however, I did not manage to do a proper review yet. Feel free to take a look at what I wrote, and I will do a proper one next week.

@ZiadMarey ZiadMarey removed the request for review from petertrr December 23, 2025 15:37
Copy link

@felix-pauck-sonarsource felix-pauck-sonarsource left a comment

Choose a reason for hiding this comment

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

The review took a while. Never worked on sonar-php before and, hence, I had to understand a couple of things first. 😉

The implementation works! 👍
The tests appear to be sufficient maybe even complete 👍, although I still had no closer look 😅.

However, I think we must improve the implementation such that it leverages the Visitor pattern. Currently, we are going back and forth in the implementation, which makes it a little hard to understand and introduces some overhead and uncertainty.

In addition to the detailed comments below, I suggest to take inspiration from this alternative implementation - again 😅:

private boolean isEmptyUsedInCondition(FunctionCallTree countCallTree, @Nullable ExpressionTree countArgument) {
    if (!(countArgument instanceof VariableIdentifierTreeImpl countArgumentVariable)) {
      return false;
    }

    Tree condition = countCallTree.getParent();
    while (condition != null) {
      if (...) {
        break;
      }
      condition = condition.getParent();
    }

    EmptyMethodCallCheck emptyCheck = new EmptyMethodCallCheck(context(), countArgumentVariable.symbol());
    condition.accept(emptyCheck);
    return emptyCheck.containsEmpty();
  }

...

  private static class EmptyMethodCallCheck extends PHPVisitorCheck {
    private static final FunctionCall EMPTY_FUNCTION_CALL = new FunctionCall("empty");

    private boolean emptyFound = false;

    CheckContext parentContext;
    Symbol countArgumentSymbol;

    EmptyMethodCallCheck(CheckContext parentContext, Symbol countArgumentSymbol) {
      this.parentContext = parentContext;
      this.countArgumentSymbol = countArgumentSymbol;
    }

    @Override
    public void visitFunctionCall(FunctionCallTree tree) {
      if (!emptyFound && isEmptyFunction(tree) && !tree.callArguments().isEmpty()) {
        ExpressionTree firstArgument = tree.callArguments().get(0).value();
        if (firstArgument.is(Tree.Kind.VARIABLE_IDENTIFIER)
          && firstArgument instanceof VariableIdentifierTreeImpl firstArgumentVariable
          && firstArgumentVariable.symbol() == countArgumentSymbol) {
          emptyFound = true;
        }
      }
      super.visitFunctionCall(tree);
    }

    private boolean isEmptyFunction(FunctionCallTree tree) {
      return EMPTY_FUNCTION_CALL.test(TreeValues.of(tree, parentContext.symbolTable()));
    }

    public boolean containsEmpty() {
      return emptyFound;
    }
  }

Copy link

@felix-pauck-sonarsource felix-pauck-sonarsource left a comment

Choose a reason for hiding this comment

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

We are getting there 😉.
Please double-check previous comments as well 🙂.

Copy link

@felix-pauck-sonarsource felix-pauck-sonarsource left a comment

Choose a reason for hiding this comment

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

Please take another look on all unresolved conversations in the PR.

Copy link

@felix-pauck-sonarsource felix-pauck-sonarsource left a comment

Choose a reason for hiding this comment

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

Let us do a sync 😉

Copy link

@felix-pauck-sonarsource felix-pauck-sonarsource left a comment

Choose a reason for hiding this comment

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

LGTM! 👍

Two comments left which are super easy to fix 😊.
Still not approving as the parent skipping (see comment below) might be critical 😅.
Will immediately approve once fixed 😉.

If you want to increase coverage (there are two uncovered lines), I think you can only do so with some mock-tests. Feel free to add them, but I think they are not needed as both lines will never be reached in a real scenario. Hence, coverage is fine as it is. 👍

@sonarqube-next
Copy link

Copy link

@felix-pauck-sonarsource felix-pauck-sonarsource left a comment

Choose a reason for hiding this comment

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

LGTM! 🎉

@ZiadMarey ZiadMarey merged commit 17d081d into master Dec 31, 2025
20 checks passed
@ZiadMarey ZiadMarey deleted the zm/SONARPHP-1721 branch December 31, 2025 11:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants