fixed #13513 - adjusted access of known int values#7181
fixed #13513 - adjusted access of known int values#7181firewave merged 11 commits intocppcheck-opensource:mainfrom
Conversation
3ac7fcc to
516a7f3
Compare
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
| if (dimension_.tok && (dimension_.tok->hasKnownIntValue() || | ||
| (dimension_.tok->isTemplateArg() && !dimension_.tok->values().empty()))) { | ||
| dimension_.num = dimension_.tok->getKnownIntValue(); | ||
| if (dimension_.tok) { | ||
| if (dimension_.tok->hasKnownIntValue()) | ||
| dimension_.num = dimension_.tok->getKnownIntValue(); | ||
| else if (dimension_.tok->isTemplateArg() && !dimension_.tok->values().empty()) { | ||
| assert(dimension_.tok->values().front().isKnown()); | ||
| dimension_.num = dimension_.tok->values().front().intvalue; | ||
| } |
There was a problem hiding this comment.
@chrchr-github Please have a look. You changed this logic a few days ago in 46781df.
There was a problem hiding this comment.
For template arguments, the values are only possible, not known. But since getKnownIntValue() just returns the first one, it is what we want in this case (I think).
There was a problem hiding this comment.
So like the previous behavior? Just unconditionally use the first value and set dimension_.known to true?
There was a problem hiding this comment.
Yes, pretty much. I imagine/hope that template arguments can have at most one value.
There was a problem hiding this comment.
Maybe we should set those values to known in the future, and prevent unwanted knownConditionTrueFalse warnings in a different way.
There was a problem hiding this comment.
I imagine/hope that template arguments can have at most one value.
I will just add a different assert.
| continue; | ||
|
|
||
| const MathLib::bigint rhsvalue = tok->astOperand2()->values().front().intvalue; | ||
| const MathLib::bigint rhsvalue = tok->astOperand2()->getKnownValue()->intvalue; |
There was a problem hiding this comment.
Because the preceding check is hasKnownValue().
There was a problem hiding this comment.
That is a bug, it should be checking for a known int value since it's creating an int value below.
There was a problem hiding this comment.
I see.
But the value is created on tok which has another hasKnownValue() check above. So that does not seem related (to me). Unless all of them need to be adjusted.
Also given the information in the other comment if this already has a non-int value and we set the int-value wouldn't that break that the case that it may only hold a single value (if that is even possible)?
There was a problem hiding this comment.
It is related, all the checks in this pass should check for int value only.
| return nullptr; | ||
| auto it = std::find_if(mImpl->mValues->begin(), mImpl->mValues->end(), std::mem_fn(&ValueFlow::Value::isKnown)); | ||
| return it == mImpl->mValues->end() ? nullptr : &*it; | ||
| } |
There was a problem hiding this comment.
There can be multiple known values of different types on a token and with the exception of int, they can be in any order. It seems like it would always be better to use the overload that takes the type.
There was a problem hiding this comment.
There can be multiple known values of different types on a token and with the exception of int, they can be in any order.
Good to know. So I guess there is no need for an intermediate step and this can simply be cleaned up.
Could that assumption be used to simplify the lookup? A getKnownIntValue() which will bail out when the size is not 1 and it is not known? That would avoid unnecessary iterations. I will of course only do that if profiling shows that it would have an impact.
Should we add some kind of validation to make sure that it is always the case? A future change might accidentally break that.
It seems like it would always be better to use the overload that takes the type.
Yeah. I just aligned the code as a first step so the intent is clear and it is easier to refactor.
There was a problem hiding this comment.
There can be multiple known values of different types on a token and with the exception of int, they can be in any order.
Good to know. So I guess there is no need for an intermediate step and this can simply be cleaned up.
What intermediate step?
Could that assumption be used to simplify the lookup? A
getKnownIntValue()which will bail out when the size is not 1 and it is not known?
The size is not guaranteed to be 1. There could be other values, such as known from other types or possible values, etc.
For known int value you don't need iteration, you can just check the first element.
It seems like it would always be better to use the overload that takes the type.
Yeah. I just aligned the code as a first step so the intent is clear and it is easier to refactor.
The overload without a type doesn't express intent and very likely its a bug in the code.
|
This should be mainly done as a first step. I tried using We should also keep the asserts to make sure that we do not introduce code which missed the preceding I will still profile to see if this doesn't introduce any regressions. |
danmar
left a comment
There was a problem hiding this comment.
I am fine with this. if @pfultz2 @chrchr-github are happy then feel free to merge..
| const ValueFlow::Value& v = arg->values().front(); | ||
| result.intvalue = v.intvalue; | ||
| result.errorPath.insert(result.errorPath.end(), v.errorPath.cbegin(), v.errorPath.cend()); | ||
| const ValueFlow::Value* v = arg->getKnownValue(ValueFlow::Value::ValueType::INT); |
There was a problem hiding this comment.
I don't have a strong opinon but well the previous hasKnownIntValue() check could be removed. and then we can check v != nullptr instead.. do it as you want..
There was a problem hiding this comment.
That check is indeed no longer necessary. The getKnownValue() changes were done after this change and I did not check the code if it could be simplified. Will do so.
| return nullptr; | ||
| auto it = std::find_if(mImpl->mValues->begin(), mImpl->mValues->end(), std::mem_fn(&ValueFlow::Value::isKnown)); | ||
| return it == mImpl->mValues->end() ? nullptr : &*it; | ||
| } |
There was a problem hiding this comment.
I don't think we should have such a function. It could lead to bugs where a different valueflow type is returned.
There was a problem hiding this comment.
Agreed.
Fortunately the subsequent cleanups made it unused and it can be removed.
…in `getKnownValue()`
|
There are more possible cleanups but I chose only those which did not require the code to be re-flowed. |
| } | ||
| if (idx->hasKnownIntValue() && idx->getKnownIntValue() == 0) | ||
| continue; |
There was a problem hiding this comment.
I filed https://trac.cppcheck.net/ticket/13732 about detecting this.
No description provided.