views:

150

answers:

2

Why does the Clang Static Analyzer (CSA) output the following message:

Although the value stored to 'self' is used in the enclosing expression, the value is never actually read from 'self'

for the following method:

- (id)init
{
    return (self = [super initWithStyle:UITableViewStyleGrouped]);
}

The code works as expected, so I'm wondering whether the code is incorrect from a technical point-of-view, this is a bug within CSA or I'm simply missing something very obvious.

FYI, I'm using this pattern because I don't want the class creating an instance of this class to be able to specify the table style.

+1  A: 

A more "proper" way to do this would be as follows:

- (id)init
{
    self = [super initWithStyle:UITableViewStyleGrouped];
    return self;
}

And it should satisfy the static analyzer

edit:

My best guess as to why Clang doesn't like that line:

When you write (self = [super initWithStyle:UITableViewStyleGrouped]), the result of the init call is stored into a temporary variable, which is then copied into self, and then it is that temporary variable that is actually returned from the method.

Although this is perfectly legal and normal behaviour (and will not break your app), the static analyzer (correctly) notices that the value stored in self is never actually read.

To illustrate, the following code:

- (id)init
{
    id temp = [super initWithStyle:UITableViewStyleGrouped];
    self = temp;
    return temp;
}

Throws the same static analyzer error.

e.James
I'm aware of this, but to return the result of an assignment expression is perfectly valid, so why does Clang not like it?
Oliver White
I'm not 100% sure, but see my edit for a plausible explanation.
e.James
I understand, thank you. I imagined that my line of code would be the same of your first code block; I wasn't aware that a temporary variable would be used. Is there a reason why this pattern is used? It seems superfluous but the Clang team know more than I do, so...
Oliver White
It has something to do with the way function return values are handled in memory. It makes more sense (from the compiler's point of view) to keep return values in a temporary variable (which is usually a register). In your one-line statement, the return value just stays in that register when the `init` method returns.
e.James
A: 

It's telling you that the self = part is unnecessary. It's not incorrect in sense of "broken or dangerous," but in that it's pointless. The variable self is just never used, so there's no point in assigning to it. It could be simply written as return [super initWithStyle:UITableViewStyleGrouped]; without any problem.

Chuck
I disagree. Check out this article by Wil Shipley. Though initially it would seem to be agreeing with you, the update at the end of the article points as to why it's important to assign the result of a super init call to self.
Oliver White
I should probably link to the article... http://www.wilshipley.com/blog/2005/07/self-stupid-init.html
Oliver White
That's a completely different situation — if you're actually going to do things after the superclass initializer, you should assign its value. But you're not doing that here. Assigning to self and then not doing anything with it is 100% pointless. It literally *can't* make a difference. That is what Clang is telling you.
Chuck