Skip to content

Improve performance in the case of many template instantiations - #8960

Open
Oipo wants to merge 2 commits into
cppcheck-opensource:mainfrom
Oipo:main
Open

Oipo wants to merge 2 commits into
cppcheck-opensource:mainfrom
Oipo:main

Conversation

@Oipo

@Oipo Oipo commented Oct 25, 2026

Copy link
Copy Markdown

Two improvements:

  1. CheckClassImpl::virtualDestructor() scanned the whole variable list and the whole token list for every (derived class, public base class) pair. With many template instantiations (for example etl) this took up to 26% of the analysis time.
  2. Tokenizer::setVarIdPass2() tried every out-of-class member definition for every class. matchMemberName() can only succeed when the innermost scope name of the class matches a name in the member's scope, in one of its "using namespace" or in its qualification. The members are now indexed by those names, in their original order, so each class only tries its candidates. The index and matchMemberName() walk the qualification with the same skipQualification().

On my own private project, the total CPU time dropped from 88.7 minutes down to 52.9 minutes. Oh, and this also fixes a false negative: new Derived < int > would never match, and it does now. See some tests I added.

Oipo added 2 commits October 25, 2026 21:27
CheckClassImpl::virtualDestructor() scanned the whole variable list and
the whole token list for every (derived class, public base class) pair.
With many template instantiations (for example etl) this took up to 26%
of the analysis time.

When the first base class is checked, the pointer variables of each type
are collected and a single pass over the tokens records, for each pointer
variable, the classes 'Derived' of a "ptr = new Derived" that is followed
by a "delete ptr;". Checking a pair is then a lookup.

This also fixes a false negative: the name of a template instantiation
such as 'Derived < int >' is a single token that contains spaces, so the
old pattern "new Derived < int >" never matched it and the pair was never
reported.

On a project using etl, glaze and Catch2 (211 translation units in two
configurations) total CPU time drops from 88.7 to 61.6 minutes, with
identical output for every translation unit.
Tokenizer::setVarIdPass2() tried every out-of-class member definition
for every class. matchMemberName() can only succeed when the innermost
scope name of the class matches a name in the member's scope, in one of
its "using namespace" or in its qualification. The members are now
indexed by those names, in their original order, so each class only
tries its candidates. The index and matchMemberName() walk the
qualification with the same skipQualification().

On the same project total CPU time drops further from 61.6 to 52.9
minutes, with identical output for every translation unit.
@dmcppcheck

Copy link
Copy Markdown

There should probably be a trac ticket for this PR. Please create it, or ask us to create it. Then the PR title should be updated.

@Oipo

Oipo commented Oct 25, 2026 via email

Copy link
Copy Markdown
Author

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