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

fixed #13513 - adjusted access of known int values #7181

Merged
merged 11 commits into from
Mar 22, 2025

Conversation

firewave
Copy link
Collaborator

@firewave firewave commented Jan 5, 2025

No description provided.

@firewave firewave force-pushed the knownint branch 2 times, most recently from 3ac7fcc to 516a7f3 Compare January 5, 2025 12:23
Copy link
Owner

@danmar danmar left a comment

Choose a reason for hiding this comment

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

I like it.. good catch

@firewave

This comment was marked as outdated.

@firewave firewave changed the title fixed #13513 - corrected access of known int values refs #13513 - adjusted access of known int values Jan 18, 2025
@firewave

This comment was marked as outdated.

@firewave

This comment was marked as outdated.

@firewave

This comment was marked as outdated.

Comment on lines 3737 to 3755
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;
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@chrchr-github Please have a look. You changed this logic a few days ago in 46781df.

Copy link
Collaborator

Choose a reason for hiding this comment

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

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).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So like the previous behavior? Just unconditionally use the first value and set dimension_.known to true?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, pretty much. I imagine/hope that template arguments can have at most one value.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe we should set those values to known in the future, and prevent unwanted knownConditionTrueFalse warnings in a different way.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I imagine/hope that template arguments can have at most one value.

I will just add a different assert.

@@ -944,7 +944,7 @@ static void valueFlowRightShift(TokenList& tokenList, const Settings& settings)
if (!tok->astOperand2()->hasKnownValue())
continue;

const MathLib::bigint rhsvalue = tok->astOperand2()->values().front().intvalue;
const MathLib::bigint rhsvalue = tok->astOperand2()->getKnownValue()->intvalue;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not getKbownIntValue?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Because the preceding check is hasKnownValue().

Copy link
Contributor

Choose a reason for hiding this comment

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

That is a bug, it should be checking for a known int value since it's creating an int value below.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

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)?

Copy link
Contributor

Choose a reason for hiding this comment

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

It is related, all the checks in this pass should check for int value only.

lib/token.cpp Outdated
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;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

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.

@firewave firewave changed the title refs #13513 - adjusted access of known int values fixed #13513 - adjusted access of known int values Jan 19, 2025
@firewave
Copy link
Collaborator Author

This should be mainly done as a first step.

I tried using getKnownValue() to avoid the duplicated fetching of the value but in many cases that wrecks the readability of the code so I am not sure if we should go with that (for now).

We should also keep the asserts to make sure that we do not introduce code which missed the preceding hasKnownIntValue() checks.

I will still profile to see if this doesn't introduce any regressions.

@firewave firewave marked this pull request as ready for review February 6, 2025 17:01
Copy link
Owner

@danmar danmar 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 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);
Copy link
Owner

Choose a reason for hiding this comment

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

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..

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

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.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done.

@firewave firewave marked this pull request as draft March 18, 2025 10:46
@firewave firewave marked this pull request as ready for review March 18, 2025 11:02
lib/token.cpp Outdated
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;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we should have such a function. It could lead to bugs where a different valueflow type is returned.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Agreed.

Fortunately the subsequent cleanups made it unused and it can be removed.

@firewave
Copy link
Collaborator Author

There are more possible cleanups but I chose only those which did not require the code to be re-flowed.

Comment on lines 1071 to -1073
}
if (idx->hasKnownIntValue() && idx->getKnownIntValue() == 0)
continue;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I filed https://trac.cppcheck.net/ticket/13732 about detecting this.

@firewave firewave merged commit 37f4de2 into danmar:main Mar 22, 2025
60 checks passed
@firewave firewave deleted the knownint branch March 22, 2025 16:49
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.

4 participants