Skip to content

provide changes after the cppcheck run#4581

Closed
guy-maurel wants to merge 3 commits into
uncrustify:masterfrom
guy-maurel:after_cppcheck
Closed

provide changes after the cppcheck run#4581
guy-maurel wants to merge 3 commits into
uncrustify:masterfrom
guy-maurel:after_cppcheck

Conversation

@guy-maurel

Copy link
Copy Markdown
Contributor

take care of the messages from cppcheck

Comment thread src/uncrustify.cpp

if ( ref->IsNullChunk()
&& !Chunk::GetHead()->IsComment()
if ( !Chunk::GetHead()->IsComment()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Je pense que le problème est plus haut et que ce changement ici peut être une erreur (car il y a des sorties de boucle "prématurés" avec les break dans ce while plus haut):

      while (  (ref = ref->GetPrev())
            && ref->IsNotNullChunk())
      {

Je suppose que ref ne peut pas devenir null et donc

      while ( (ref = ref->GetPrev())->IsNotNullChunk())
      {

est la solution qui permets de rester au plus proche de ce qui est déjà fait avec moins de risque d'effets de bord.

@micheleCTDEAdmin micheleCTDEAdmin Nov 30, 2025

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The two snippers of code in the comment above do exactly the same thing. Why would the second be better than the first? It reduce code readability.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If we get at this point of the code, ref is definitely not a null chuck, so the propose code from Guy is correct.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The original code looks like this:

      while (  (ref = ref->GetPrev())
            && ref->IsNotNullChunk())
      {
          if(some_other_condition) { break; }
      }
      if (  ref->IsNullChunk()
         && !Chunk::GetHead()->IsComment()
         && Chunk::GetHead()->GetParentType() == type)
      {
      // [...]
      }

For the compiler, the static analysis tool and any first inspecxtion of the code, this is a test if (ref = ref->GetPrev()) is not null, and if true, a test that ref->IsNotNullChunk() is not "falsy".

So it looks like the while loop can end when ref became NULL and therefore the test ref->IsNullChunk() in the test after the loop would reference a NULL pointer.
So cppcheck indicates that this looks like an issue.

Readabomotu os a point of view, but the next alternative is only one test to the compiler and the static analysis tool - and also suggests to the reager that ref can not be null (which can be reinforced with a comment).

while ((ref = ref->GetPrev())->IsNotNullChunk())

The following is an alternative: still two statements but only one test.

while (ref = ref->GetPrev(), ref->IsNotNullChunk())
{

My other observation is that removing the ref->IsNullChunk() can have other side effects as the while loop can exit when that conditioni is false, so removing the condition from the test after the loop requires deeper analysis to ensure that the behavior did not change.

uncrustify/src/uncrustify.cpp

Lines 1862 to 1865 in ee17aee

if ( ref->IsNullChunk()
&& !Chunk::GetHead()->IsComment()
&& Chunk::GetHead()->GetParentType() == type)
{

@micheleCTDEAdmin indicats:

If we get at this point of the code, ref is definitely not a null chuck, so the propose code from Guy is correct.

In the original while test I see ref->IsNotNullChunk(). So I conclude that the loop can exit with:

  • ref->IsNullChunk() being true (so it would be a null chunk) when exited because of the loop condition,
  • but ref->IsNullChunk() being false if the loop exits because of a break; inside the loop.

Of course the test cases pass, so theyt do not proof that ref->IsNullChunk() can be false or have a negative side-effect if it is false.

However, I leave the in-depth analysis up to you as you're more familiar with the code.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

ref is a Chuck. A null is a valid Chunk and the way the "null chuck" logic has been designed, it ensures that ref will always point to a Chunk object, which could be the NullChunk. A NullChuck is not a nullptr, by the way.
I looked at the code earlier today and indeed at the point ref will point to a valid chuck, because otherwise the while loop would have either ended or skipped the iteration

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • If the while loop ends because of a break, then 'ref->IsNullChunk()' is false and therefore with this condition removed from the test on line 1862, the statements in that test block are now executed (before they were not).
  • Apparently according to your analysis, the loop can never end because of 'ref->IsNotNullChunk() returning false because after the loop the Chunk is always a valid Chuck, so then this test is futile and this basically is the same as while(1) {ref=ref->GetPrev(); /* rest of block */;
  • The NullChuck is a Null Object pattern. So the test on "ref = ref->GetPrev()" not being null is futile.

@micheleCTDE micheleCTDE Jan 8, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I have checked again, the first time I must have been confused by the indentation and I made a wrong comment. If we get at line 1862, the chuck may or may not be a NullChunk, depending on how the while loop terminated. So we need to keep the check for NullChunk in the "if":

if (  ref->IsNullChunk()
   && !Chunk::GetHead()->IsComment()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Apparently according to your analysis, the loop can never end because of 'ref->IsNotNullChunk() returning false because after the loop the Chunk is always a valid Chuck

This is incorrect. The NullChunk is a valid chunk object, but it has a special meaning. so the check for a chuck to be or not to be the NullChunk is very meaningful.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Apparently according to your analysis, the loop can never end because of 'ref->IsNotNullChunk() returning false because after the loop the Chunk is always a valid Chuck

This is incorrect. The NullChunk is a valid chunk object, but it has a special meaning. so the check for a chuck to be or not to be the NullChunk is very meaningful.

So we agree on this ;-) . My observation was that based on the fact that the test ref->IsNullChunk() was removed (implicitly assuming that is is true) that the new code assumed that ref->IsNotNullChunk() is always false (opposite) leading to the conclusion that keeping ref->IsNullChunk() is the right thing to do.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

yes, we agree on this point. Sorry for the initial wrong comment.

@mdeweerd

mdeweerd commented Nov 26, 2025

Copy link
Copy Markdown
Contributor

J'ai rebasé le code de l'autre PR #4579 et il reste le formatage uncrustify du code source et:

src/unc_text.cpp(95): style (constParameterReference): Parameter 'c0' can be declared as reference to const

@micheleCTDEAdmin micheleCTDEAdmin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We need to fix the issue in src/tokenizer/combine_fix_mark.cpp before we can merge this. At least put back the if check, although it is clear that even the original code is wrong.

Comment thread src/tokenizer/combine_fix_mark.cpp Outdated
{
tmp2->SetType(CT_FUNC_TYPE);
}
tmp2->SetType(CT_FUNC_TYPE);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Something is very wrong here, even in the original code. At line 1405 we check if tmp2 is not the null chunk. If it is not, we execute the if-body at lines 1406-1414. If the if failed, we enter the else-body at lines 1416-1422. Setting tmp2 to CT_FUNC_TYPE is wrong, because tmp2 is a null chuck, it can't be a function.
The original code is wrong as well, but at least the if at original line 1420 would have prevented the additional problem, because at that line tmp2 is indeed the null chuck.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Actually we can completely remove the original 4 lines of code at 1420-1423, because that "if" was always false.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This needs to be changed before we can merge it, or the PR will introduce a serious bug because it could set the type of the NullChunk to CT_FUNC_TYPE, which is obviously wrong.

Comment thread src/uncrustify.cpp

if ( ref->IsNullChunk()
&& !Chunk::GetHead()->IsComment()
if ( !Chunk::GetHead()->IsComment()

@micheleCTDEAdmin micheleCTDEAdmin Nov 30, 2025

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The two snippers of code in the comment above do exactly the same thing. Why would the second be better than the first? It reduce code readability.

Comment thread src/uncrustify.cpp

if ( ref->IsNullChunk()
&& !Chunk::GetHead()->IsComment()
if ( !Chunk::GetHead()->IsComment()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If we get at this point of the code, ref is definitely not a null chuck, so the propose code from Guy is correct.

@gmaurel

gmaurel commented Jan 23, 2026

Copy link
Copy Markdown
Collaborator

@micheleCTDEAdmin
Please de block the PR
Thanks

@micheleCTDE

Copy link
Copy Markdown
Collaborator

@micheleCTDEAdmin Please de block the PR Thanks

This PR needs to be fixed because in some cases it would modify the NullChunk incorrectly. See this comment

@micheleCTDE

Copy link
Copy Markdown
Collaborator

@gmaurel if you want, I can make a fix for it

@guy-maurel

Copy link
Copy Markdown
Contributor Author

YES! ! !
It would be fine!
Thanks

@micheleCTDE

micheleCTDE commented Jan 25, 2026

Copy link
Copy Markdown
Collaborator

YES! ! ! It would be fine! Thanks

@gmaurel I can't push a commit on your branch, but the only change required is to delete two lines of code, as per this patch:

--- a/src/tokenizer/combine_fix_mark.cpp
+++ b/src/tokenizer/combine_fix_mark.cpp
@@ -1416,8 +1416,6 @@ void mark_function(Chunk *pc)
          {
             LOG_FMT(LFCN, "%s(%d): orig line is %zu, orig col is %zu, function type, changing '%s' into a type\n",
                     __func__, __LINE__, pc->GetOrigLine(), pc->GetOrigCol(), pc->Text());
-
-            tmp2->SetType(CT_FUNC_TYPE);
             flag_parens(paren_open, PCF_NONE, CT_PAREN_OPEN, CT_FUNC_TYPE, false);
          }
          pc->SetType(CT_TYPE);

I tested locally and all the tests pass. Please update the PR as above and then we can proceed with merging.

@micheleCTDEAdmin

Copy link
Copy Markdown
Collaborator

Now that PR #4644 has been merged, we can update this PR with the same change, then we can proceed with merging.

@guy-maurel guy-maurel closed this Jun 19, 2026
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.

5 participants