diff --git a/Makefile b/Makefile
index 5a348e27001..684e79179cf 100644
--- a/Makefile
+++ b/Makefile
@@ -208,7 +208,6 @@ LIBOBJ =      $(libcppdir)/valueflow.o \
               $(libcppdir)/addoninfo.o \
               $(libcppdir)/analyzerinfo.o \
               $(libcppdir)/astutils.o \
-              $(libcppdir)/check.o \
               $(libcppdir)/check64bit.o \
               $(libcppdir)/checkassert.o \
               $(libcppdir)/checkautovariables.o \
@@ -221,6 +220,7 @@ LIBOBJ =      $(libcppdir)/valueflow.o \
               $(libcppdir)/checkersreport.o \
               $(libcppdir)/checkexceptionsafety.o \
               $(libcppdir)/checkfunctions.o \
+              $(libcppdir)/checkimpl.o \
               $(libcppdir)/checkinternal.o \
               $(libcppdir)/checkio.o \
               $(libcppdir)/checkleakautovar.o \
@@ -483,7 +483,7 @@ check-nonneg:
 
 ###### Build
 
-$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/calculate.h lib/check.h lib/checkers.h lib/checkuninitvar.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/forwardanalyzer.h lib/infer.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/regex.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vf_analyzers.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h
+$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/calculate.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkuninitvar.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/forwardanalyzer.h lib/infer.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/regex.h lib/reverseanalyzer.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vf_analyzers.h lib/vf_common.h lib/vf_settokenvalue.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/valueflow.cpp
 
 $(libcppdir)/tokenize.o: lib/tokenize.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/astutils.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/summaries.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
@@ -498,31 +498,28 @@ $(libcppdir)/addoninfo.o: lib/addoninfo.cpp externals/picojson/picojson.h lib/ad
 $(libcppdir)/analyzerinfo.o: lib/analyzerinfo.cpp externals/tinyxml2/tinyxml2.h lib/analyzerinfo.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/mathlib.h lib/path.h lib/platform.h lib/standards.h lib/utils.h lib/xml.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/analyzerinfo.cpp
 
-$(libcppdir)/astutils.o: lib/astutils.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkclass.h lib/checkers.h lib/config.h lib/errortypes.h lib/findtoken.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vfvalue.h
+$(libcppdir)/astutils.o: lib/astutils.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/findtoken.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/valueflow.h lib/valueptr.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/astutils.cpp
 
-$(libcppdir)/check.o: lib/check.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
-	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/check.cpp
-
-$(libcppdir)/check64bit.o: lib/check64bit.cpp lib/addoninfo.h lib/check.h lib/check64bit.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
+$(libcppdir)/check64bit.o: lib/check64bit.cpp lib/addoninfo.h lib/check.h lib/check64bit.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/check64bit.cpp
 
-$(libcppdir)/checkassert.o: lib/checkassert.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkassert.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
+$(libcppdir)/checkassert.o: lib/checkassert.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkassert.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkassert.cpp
 
-$(libcppdir)/checkautovariables.o: lib/checkautovariables.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkautovariables.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
+$(libcppdir)/checkautovariables.o: lib/checkautovariables.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkautovariables.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkautovariables.cpp
 
-$(libcppdir)/checkbool.o: lib/checkbool.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkbool.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
+$(libcppdir)/checkbool.o: lib/checkbool.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkbool.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbool.cpp
 
-$(libcppdir)/checkbufferoverrun.o: lib/checkbufferoverrun.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkbufferoverrun.h lib/checkers.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vf_common.h lib/vfvalue.h lib/xml.h
+$(libcppdir)/checkbufferoverrun.o: lib/checkbufferoverrun.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkbufferoverrun.h lib/checkers.h lib/checkimpl.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vf_common.h lib/vfvalue.h lib/xml.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbufferoverrun.cpp
 
-$(libcppdir)/checkclass.o: lib/checkclass.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkclass.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
+$(libcppdir)/checkclass.o: lib/checkclass.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/astutils.h lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkclass.cpp
 
-$(libcppdir)/checkcondition.o: lib/checkcondition.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkcondition.h lib/checkers.h lib/checkother.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
+$(libcppdir)/checkcondition.o: lib/checkcondition.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkcondition.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkcondition.cpp
 
 $(libcppdir)/checkers.o: lib/checkers.cpp lib/checkers.h lib/config.h
@@ -534,58 +531,61 @@ $(libcppdir)/checkersidmapping.o: lib/checkersidmapping.cpp lib/checkers.h lib/c
 $(libcppdir)/checkersreport.o: lib/checkersreport.cpp lib/addoninfo.h lib/checkers.h lib/checkersreport.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkersreport.cpp
 
-$(libcppdir)/checkexceptionsafety.o: lib/checkexceptionsafety.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkexceptionsafety.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
+$(libcppdir)/checkexceptionsafety.o: lib/checkexceptionsafety.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkexceptionsafety.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkexceptionsafety.cpp
 
-$(libcppdir)/checkfunctions.o: lib/checkfunctions.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkfunctions.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
+$(libcppdir)/checkfunctions.o: lib/checkfunctions.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkfunctions.h lib/checkimpl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkfunctions.cpp
 
-$(libcppdir)/checkinternal.o: lib/checkinternal.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkinternal.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
+$(libcppdir)/checkimpl.o: lib/checkimpl.cpp lib/addoninfo.h lib/checkers.h lib/checkimpl.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
+	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkimpl.cpp
+
+$(libcppdir)/checkinternal.o: lib/checkinternal.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkinternal.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkinternal.cpp
 
-$(libcppdir)/checkio.o: lib/checkio.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkio.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
+$(libcppdir)/checkio.o: lib/checkio.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkio.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkio.cpp
 
-$(libcppdir)/checkleakautovar.o: lib/checkleakautovar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkleakautovar.h lib/checkmemoryleak.h lib/checknullpointer.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
+$(libcppdir)/checkleakautovar.o: lib/checkleakautovar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkleakautovar.h lib/checkmemoryleak.h lib/checknullpointer.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkleakautovar.cpp
 
-$(libcppdir)/checkmemoryleak.o: lib/checkmemoryleak.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkmemoryleak.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
+$(libcppdir)/checkmemoryleak.o: lib/checkmemoryleak.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkmemoryleak.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkmemoryleak.cpp
 
-$(libcppdir)/checknullpointer.o: lib/checknullpointer.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checknullpointer.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
+$(libcppdir)/checknullpointer.o: lib/checknullpointer.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checknullpointer.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/findtoken.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checknullpointer.cpp
 
-$(libcppdir)/checkother.o: lib/checkother.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkother.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
+$(libcppdir)/checkother.o: lib/checkother.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkother.cpp
 
-$(libcppdir)/checkpostfixoperator.o: lib/checkpostfixoperator.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkpostfixoperator.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
+$(libcppdir)/checkpostfixoperator.o: lib/checkpostfixoperator.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkpostfixoperator.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkpostfixoperator.cpp
 
-$(libcppdir)/checks.o: lib/checks.cpp lib/check.h lib/check64bit.h lib/checkassert.h lib/checkautovariables.h lib/checkbool.h lib/checkbufferoverrun.h lib/checkclass.h lib/checkcondition.h lib/checkexceptionsafety.h lib/checkfunctions.h lib/checkinternal.h lib/checkio.h lib/checkleakautovar.h lib/checkmemoryleak.h lib/checknullpointer.h lib/checkother.h lib/checkpostfixoperator.h lib/checks.h lib/checksizeof.h lib/checkstl.h lib/checkstring.h lib/checktype.h lib/checkuninitvar.h lib/checkunusedvar.h lib/checkvaarg.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/standards.h lib/vfvalue.h
+$(libcppdir)/checks.o: lib/checks.cpp lib/check.h lib/check64bit.h lib/checkassert.h lib/checkautovariables.h lib/checkbool.h lib/checkbufferoverrun.h lib/checkclass.h lib/checkcondition.h lib/checkexceptionsafety.h lib/checkfunctions.h lib/checkimpl.h lib/checkinternal.h lib/checkio.h lib/checkleakautovar.h lib/checkmemoryleak.h lib/checknullpointer.h lib/checkother.h lib/checkpostfixoperator.h lib/checks.h lib/checksizeof.h lib/checkstl.h lib/checkstring.h lib/checktype.h lib/checkuninitvar.h lib/checkunusedvar.h lib/checkvaarg.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/standards.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checks.cpp
 
-$(libcppdir)/checksizeof.o: lib/checksizeof.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checksizeof.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
+$(libcppdir)/checksizeof.o: lib/checksizeof.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checksizeof.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checksizeof.cpp
 
-$(libcppdir)/checkstl.o: lib/checkstl.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checknullpointer.h lib/checkstl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/pathanalysis.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
+$(libcppdir)/checkstl.o: lib/checkstl.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checknullpointer.h lib/checkstl.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/pathanalysis.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkstl.cpp
 
-$(libcppdir)/checkstring.o: lib/checkstring.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkstring.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
+$(libcppdir)/checkstring.o: lib/checkstring.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkstring.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkstring.cpp
 
-$(libcppdir)/checktype.o: lib/checktype.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checktype.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
+$(libcppdir)/checktype.o: lib/checktype.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checktype.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checktype.cpp
 
-$(libcppdir)/checkuninitvar.o: lib/checkuninitvar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checknullpointer.h lib/checkuninitvar.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
+$(libcppdir)/checkuninitvar.o: lib/checkuninitvar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checknullpointer.h lib/checkuninitvar.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkuninitvar.cpp
 
 $(libcppdir)/checkunusedfunctions.o: lib/checkunusedfunctions.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/analyzerinfo.h lib/astutils.h lib/checkers.h lib/checkunusedfunctions.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkunusedfunctions.cpp
 
-$(libcppdir)/checkunusedvar.o: lib/checkunusedvar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkunusedvar.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
+$(libcppdir)/checkunusedvar.o: lib/checkunusedvar.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkunusedvar.h lib/config.h lib/errortypes.h lib/fwdanalysis.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkunusedvar.cpp
 
-$(libcppdir)/checkvaarg.o: lib/checkvaarg.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkvaarg.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
+$(libcppdir)/checkvaarg.o: lib/checkvaarg.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkvaarg.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
 	$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkvaarg.cpp
 
 $(libcppdir)/clangimport.o: lib/clangimport.cpp lib/clangimport.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
@@ -744,28 +744,28 @@ test/main.o: test/main.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/c
 test/options.o: test/options.cpp lib/config.h lib/timer.h test/options.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/options.cpp
 
-test/test64bit.o: test/test64bit.cpp lib/addoninfo.h lib/check.h lib/check64bit.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/test64bit.o: test/test64bit.cpp lib/addoninfo.h lib/check.h lib/check64bit.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/test64bit.cpp
 
 test/testanalyzerinformation.o: test/testanalyzerinformation.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h lib/xml.h test/fixture.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testanalyzerinformation.cpp
 
-test/testassert.o: test/testassert.cpp lib/addoninfo.h lib/check.h lib/checkassert.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testassert.o: test/testassert.cpp lib/addoninfo.h lib/check.h lib/checkassert.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testassert.cpp
 
 test/testastutils.o: test/testastutils.cpp lib/addoninfo.h lib/astutils.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testastutils.cpp
 
-test/testautovariables.o: test/testautovariables.cpp lib/addoninfo.h lib/check.h lib/checkautovariables.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testautovariables.o: test/testautovariables.cpp lib/addoninfo.h lib/check.h lib/checkautovariables.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testautovariables.cpp
 
-test/testbool.o: test/testbool.cpp lib/addoninfo.h lib/check.h lib/checkbool.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testbool.o: test/testbool.cpp lib/addoninfo.h lib/check.h lib/checkbool.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testbool.cpp
 
-test/testbufferoverrun.o: test/testbufferoverrun.cpp lib/addoninfo.h lib/check.h lib/checkbufferoverrun.h lib/checkers.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
+test/testbufferoverrun.o: test/testbufferoverrun.cpp lib/addoninfo.h lib/check.h lib/checkbufferoverrun.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testbufferoverrun.cpp
 
-test/testcharvar.o: test/testcharvar.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testcharvar.o: test/testcharvar.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcharvar.cpp
 
 test/testcheck.o: test/testcheck.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checks.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h
@@ -777,7 +777,7 @@ test/testcheckersreport.o: test/testcheckersreport.cpp lib/addoninfo.h lib/check
 test/testclangimport.o: test/testclangimport.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/clangimport.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testclangimport.cpp
 
-test/testclass.o: test/testclass.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
+test/testclass.o: test/testclass.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testclass.cpp
 
 test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h
@@ -786,10 +786,10 @@ test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlinelogger.h cli/cmd
 test/testcolor.o: test/testcolor.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcolor.cpp
 
-test/testcondition.o: test/testcondition.cpp lib/addoninfo.h lib/check.h lib/checkcondition.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testcondition.o: test/testcondition.cpp lib/addoninfo.h lib/check.h lib/checkcondition.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcondition.cpp
 
-test/testconstructors.o: test/testconstructors.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testconstructors.o: test/testconstructors.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testconstructors.cpp
 
 test/testcppcheck.o: test/testcppcheck.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h
@@ -798,7 +798,7 @@ test/testcppcheck.o: test/testcppcheck.cpp externals/simplecpp/simplecpp.h lib/a
 test/testerrorlogger.o: test/testerrorlogger.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testerrorlogger.cpp
 
-test/testexceptionsafety.o: test/testexceptionsafety.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkexceptionsafety.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testexceptionsafety.o: test/testexceptionsafety.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkexceptionsafety.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testexceptionsafety.cpp
 
 test/testexecutor.o: test/testexecutor.cpp cli/executor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
@@ -813,7 +813,7 @@ test/testfilesettings.o: test/testfilesettings.cpp lib/addoninfo.h lib/check.h l
 test/testfrontend.o: test/testfrontend.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testfrontend.cpp
 
-test/testfunctions.o: test/testfunctions.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkfunctions.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testfunctions.o: test/testfunctions.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkfunctions.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testfunctions.cpp
 
 test/testgarbage.o: test/testgarbage.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checks.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
@@ -822,16 +822,16 @@ test/testgarbage.o: test/testgarbage.cpp lib/addoninfo.h lib/check.h lib/checker
 test/testimportproject.o: test/testimportproject.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h lib/xml.h test/fixture.h test/redirect.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testimportproject.cpp
 
-test/testincompletestatement.o: test/testincompletestatement.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testincompletestatement.o: test/testincompletestatement.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testincompletestatement.cpp
 
-test/testinternal.o: test/testinternal.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkinternal.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testinternal.o: test/testinternal.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkinternal.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testinternal.cpp
 
-test/testio.o: test/testio.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkio.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testio.o: test/testio.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkio.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testio.cpp
 
-test/testleakautovar.o: test/testleakautovar.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkleakautovar.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testleakautovar.o: test/testleakautovar.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkleakautovar.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testleakautovar.cpp
 
 test/testlibrary.o: test/testlibrary.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
@@ -840,16 +840,16 @@ test/testlibrary.o: test/testlibrary.cpp lib/addoninfo.h lib/check.h lib/checker
 test/testmathlib.o: test/testmathlib.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testmathlib.cpp
 
-test/testmemleak.o: test/testmemleak.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkmemoryleak.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
+test/testmemleak.o: test/testmemleak.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkmemoryleak.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testmemleak.cpp
 
-test/testnullpointer.o: test/testnullpointer.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checknullpointer.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
+test/testnullpointer.o: test/testnullpointer.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checknullpointer.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testnullpointer.cpp
 
 test/testoptions.o: test/testoptions.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h test/options.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testoptions.cpp
 
-test/testother.o: test/testother.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testother.o: test/testother.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testother.cpp
 
 test/testpath.o: test/testpath.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
@@ -861,7 +861,7 @@ test/testpathmatch.o: test/testpathmatch.cpp lib/addoninfo.h lib/check.h lib/che
 test/testplatform.o: test/testplatform.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h lib/xml.h test/fixture.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testplatform.cpp
 
-test/testpostfixoperator.o: test/testpostfixoperator.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkpostfixoperator.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testpostfixoperator.o: test/testpostfixoperator.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkpostfixoperator.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testpostfixoperator.cpp
 
 test/testpreprocessor.o: test/testpreprocessor.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
@@ -897,16 +897,16 @@ test/testsimplifyusing.o: test/testsimplifyusing.cpp lib/addoninfo.h lib/check.h
 test/testsingleexecutor.o: test/testsingleexecutor.cpp cli/executor.h cli/singleexecutor.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsingleexecutor.cpp
 
-test/testsizeof.o: test/testsizeof.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checksizeof.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testsizeof.o: test/testsizeof.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checksizeof.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsizeof.cpp
 
 test/teststandards.o: test/teststandards.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/teststandards.cpp
 
-test/teststl.o: test/teststl.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkstl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/teststl.o: test/teststl.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkstl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/teststl.cpp
 
-test/teststring.o: test/teststring.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkstring.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/teststring.o: test/teststring.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkstring.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/teststring.cpp
 
 test/testsummaries.o: test/testsummaries.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/summaries.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
@@ -936,25 +936,25 @@ test/testtokenlist.o: test/testtokenlist.cpp externals/simplecpp/simplecpp.h lib
 test/testtokenrange.o: test/testtokenrange.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/tokenrange.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtokenrange.cpp
 
-test/testtype.o: test/testtype.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checktype.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testtype.o: test/testtype.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checktype.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testtype.cpp
 
-test/testuninitvar.o: test/testuninitvar.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkuninitvar.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
+test/testuninitvar.o: test/testuninitvar.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkuninitvar.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testuninitvar.cpp
 
 test/testunusedfunctions.o: test/testunusedfunctions.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkunusedfunctions.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testunusedfunctions.cpp
 
-test/testunusedprivfunc.o: test/testunusedprivfunc.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testunusedprivfunc.o: test/testunusedprivfunc.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/checkimpl.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testunusedprivfunc.cpp
 
-test/testunusedvar.o: test/testunusedvar.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/checkunusedvar.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testunusedvar.o: test/testunusedvar.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkunusedvar.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testunusedvar.cpp
 
 test/testutils.o: test/testutils.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/utils.h test/fixture.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testutils.cpp
 
-test/testvaarg.o: test/testvaarg.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkvaarg.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
+test/testvaarg.o: test/testvaarg.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/checkimpl.h lib/checkvaarg.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
 	$(CXX) ${INCLUDE_FOR_TEST} ${CFLAGS_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testvaarg.cpp
 
 test/testvalueflow.o: test/testvalueflow.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/regex.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
diff --git a/lib/astutils.cpp b/lib/astutils.cpp
index 56a9489d00e..8dfd03596d3 100644
--- a/lib/astutils.cpp
+++ b/lib/astutils.cpp
@@ -2157,7 +2157,7 @@ bool isWithoutSideEffects(const Token* tok, bool checkArrayAccess, bool checkRef
     if (tok && tok->varId()) {
         const Variable* var = tok->variable();
         return var && ((!var->isClass() && (checkReference || !var->isReference())) || var->isPointer() ||
-                       (checkArrayAccess ? var->isArray() || (var->isStlType() && !var->isStlType(CheckClass::stl_containers_not_const)) : var->isStlType()));
+                       (checkArrayAccess ? var->isArray() || (var->isStlType() && !var->isStlType(CheckClassImpl::stl_containers_not_const)) : var->isStlType()));
     }
     return true;
 }
diff --git a/lib/check.h b/lib/check.h
index 9a50e64baa1..06febbd5eaa 100644
--- a/lib/check.h
+++ b/lib/check.h
@@ -22,7 +22,6 @@
 //---------------------------------------------------------------------------
 
 #include "config.h"
-#include "errortypes.h"
 
 #include <list>
 #include <string>
@@ -36,14 +35,8 @@ namespace CTU {
     class FileInfo;
 }
 
-namespace ValueFlow {
-    class Value;
-}
-
 class Settings;
-class Token;
 class ErrorLogger;
-class ErrorMessage;
 class Tokenizer;
 
 /** Use WRONG_DATA in checkers to mark conditions that check that data is correct */
@@ -59,17 +52,9 @@ class Tokenizer;
 class CPPCHECKLIB Check {
 public:
     /** This constructor is used when registering the CheckClass */
-    explicit Check(std::string aname);
-
-protected:
-    /** This constructor is used when running checks. */
-    Check(std::string aname, const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : mTokenizer(tokenizer), mSettings(settings), mErrorLogger(errorLogger), mName(std::move(aname)) {}
-
-private:
-    static std::list<Check *> &instances_internal();
-
-public:
+    explicit Check(std::string aname)
+        : mName(std::move(aname))
+    {}
     virtual ~Check() = default;
 
     Check(const Check &) = delete;
@@ -89,13 +74,6 @@ class CPPCHECKLIB Check {
     /** get information about this class, used to generate documentation */
     virtual std::string classInfo() const = 0;
 
-    /**
-     * Write given error to stdout in xml format.
-     * This is for for printout out the error list with --errorlist
-     * @param errmsg Error message to write
-     */
-    static void writeToErrorList(const ErrorMessage &errmsg);
-
     /** Base class used for whole-program analysis */
     class CPPCHECKLIB FileInfo {
     public:
@@ -121,40 +99,6 @@ class CPPCHECKLIB Check {
         return false;
     }
 
-protected:
-    static std::string getMessageId(const ValueFlow::Value &value, const char id[]);
-
-    const Tokenizer* const mTokenizer{};
-    const Settings* const mSettings{};
-    ErrorLogger* const mErrorLogger{};
-
-    /** report an error */
-    void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg) {
-        reportError(tok, severity, id, msg, CWE(0U), Certainty::normal);
-    }
-
-    /** report an error */
-    void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg, const CWE &cwe, Certainty certainty) {
-        const std::list<const Token *> callstack(1, tok);
-        reportError(callstack, severity, id, msg, cwe, certainty);
-    }
-
-    /** report an error */
-    void reportError(const std::list<const Token *> &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe, Certainty certainty);
-
-    void reportError(ErrorPath errorPath, Severity severity, const char id[], const std::string &msg, const CWE &cwe, Certainty certainty);
-
-    /** log checker */
-    void logChecker(const char id[]);
-
-    ErrorPath getErrorPath(const Token* errtok, const ValueFlow::Value* value, std::string bug) const;
-
-    /**
-     * Use WRONG_DATA in checkers when you check for wrong data. That
-     * will call this method
-     */
-    bool wrongData(const Token *tok, const char *str);
-
 private:
     const std::string mName;
 };
diff --git a/lib/check64bit.cpp b/lib/check64bit.cpp
index b33ab5bdbcb..e1e6f086ff3 100644
--- a/lib/check64bit.cpp
+++ b/lib/check64bit.cpp
@@ -51,7 +51,7 @@ static bool isFunctionPointer(const Token* tok)
     return Tokenizer::isFunctionPointer(tok->variable()->nameToken());
 }
 
-void Check64BitPortability::pointerassignment()
+void Check64BitPortabilityImpl::pointerassignment()
 {
     if (!mSettings->severity.isEnabled(Severity::portability))
         return;
@@ -139,7 +139,7 @@ void Check64BitPortability::pointerassignment()
     }
 }
 
-void Check64BitPortability::assignmentAddressToIntegerError(const Token *tok)
+void Check64BitPortabilityImpl::assignmentAddressToIntegerError(const Token *tok)
 {
     reportError(tok, Severity::portability,
                 "AssignmentAddressToInteger",
@@ -150,7 +150,7 @@ void Check64BitPortability::assignmentAddressToIntegerError(const Token *tok)
                 "way is to store addresses only in pointer types (or typedefs like uintptr_t).", CWE758, Certainty::normal);
 }
 
-void Check64BitPortability::assignmentIntegerToAddressError(const Token *tok)
+void Check64BitPortabilityImpl::assignmentIntegerToAddressError(const Token *tok)
 {
     reportError(tok, Severity::portability,
                 "AssignmentIntegerToAddress",
@@ -161,7 +161,7 @@ void Check64BitPortability::assignmentIntegerToAddressError(const Token *tok)
                 "way is to store addresses only in pointer types (or typedefs like uintptr_t).", CWE758, Certainty::normal);
 }
 
-void Check64BitPortability::returnPointerError(const Token *tok)
+void Check64BitPortabilityImpl::returnPointerError(const Token *tok)
 {
     reportError(tok, Severity::portability,
                 "CastAddressToIntegerAtReturn",
@@ -172,7 +172,7 @@ void Check64BitPortability::returnPointerError(const Token *tok)
                 "to 32-bit integer. The safe way is to return a type such as intptr_t.", CWE758, Certainty::normal);
 }
 
-void Check64BitPortability::returnIntegerError(const Token *tok)
+void Check64BitPortabilityImpl::returnIntegerError(const Token *tok)
 {
     reportError(tok, Severity::portability,
                 "CastIntegerToAddressAtReturn",
@@ -185,13 +185,13 @@ void Check64BitPortability::returnIntegerError(const Token *tok)
 
 void Check64BitPortability::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    Check64BitPortability check64BitPortability(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    Check64BitPortabilityImpl check64BitPortability(&tokenizer, &tokenizer.getSettings(), errorLogger);
     check64BitPortability.pointerassignment();
 }
 
 void Check64BitPortability::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    Check64BitPortability c(nullptr, settings, errorLogger);
+    Check64BitPortabilityImpl c(nullptr, settings, errorLogger);
     c.assignmentAddressToIntegerError(nullptr);
     c.assignmentIntegerToAddressError(nullptr);
     c.returnIntegerError(nullptr);
diff --git a/lib/check64bit.h b/lib/check64bit.h
index 79397e98e5f..1996d91ee23 100644
--- a/lib/check64bit.h
+++ b/lib/check64bit.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <string>
@@ -44,36 +45,35 @@ class CPPCHECKLIB Check64BitPortability : public Check {
 
 public:
     /** This constructor is used when registering the Check64BitPortability */
-    Check64BitPortability() : Check(myName()) {}
+    Check64BitPortability() : Check("64-bit portability") {}
 
 private:
-    /** This constructor is used when running checks. */
-    Check64BitPortability(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     /** @brief Run checks against the normal token list */
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
-    /** Check for pointer assignment */
-    void pointerassignment();
-
-    void assignmentAddressToIntegerError(const Token *tok);
-    void assignmentIntegerToAddressError(const Token *tok);
-    void returnIntegerError(const Token *tok);
-    void returnPointerError(const Token *tok);
-
     void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
 
-    static std::string myName() {
-        return "64-bit portability";
-    }
-
     std::string classInfo() const override {
         return "Check if there is 64-bit portability issues:\n"
                "- assign address to/from int/long\n"
                "- casting address from/to integer when returning from function\n";
     }
 };
+
+class CPPCHECKLIB Check64BitPortabilityImpl : public CheckImpl {
+public:
+    /** This constructor is used when running checks. */
+    Check64BitPortabilityImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
+    /** Check for pointer assignment */
+    void pointerassignment();
+
+    void assignmentAddressToIntegerError(const Token *tok);
+    void assignmentIntegerToAddressError(const Token *tok);
+    void returnIntegerError(const Token *tok);
+    void returnPointerError(const Token *tok);
+};
 /// @}
 //---------------------------------------------------------------------------
 #endif // check64bitH
diff --git a/lib/checkassert.cpp b/lib/checkassert.cpp
index ce2d7c62169..5242b595e67 100644
--- a/lib/checkassert.cpp
+++ b/lib/checkassert.cpp
@@ -39,7 +39,7 @@
 // CWE ids used
 static const CWE CWE398(398U);   // Indicator of Poor Code Quality
 
-void CheckAssert::assertWithSideEffects()
+void CheckAssertImpl::assertWithSideEffects()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -117,7 +117,7 @@ void CheckAssert::assertWithSideEffects()
 //---------------------------------------------------------------------------
 
 
-void CheckAssert::sideEffectInAssertError(const Token *tok, const std::string& functionName)
+void CheckAssertImpl::sideEffectInAssertError(const Token *tok, const std::string& functionName)
 {
     reportError(tok, Severity::warning,
                 "assertWithSideEffect",
@@ -129,7 +129,7 @@ void CheckAssert::sideEffectInAssertError(const Token *tok, const std::string& f
                 "builds, this is a bug.", CWE398, Certainty::normal);
 }
 
-void CheckAssert::assignmentInAssertError(const Token *tok, const std::string& varname)
+void CheckAssertImpl::assignmentInAssertError(const Token *tok, const std::string& varname)
 {
     reportError(tok, Severity::warning,
                 "assignmentInAssert",
@@ -142,7 +142,7 @@ void CheckAssert::assignmentInAssertError(const Token *tok, const std::string& v
 }
 
 // checks if side effects happen on the variable prior to tmp
-void CheckAssert::checkVariableAssignment(const Token* assignTok, const Scope *assertionScope)
+void CheckAssertImpl::checkVariableAssignment(const Token* assignTok, const Scope *assertionScope)
 {
     if (!assignTok->isAssignmentOp() && assignTok->tokType() != Token::eIncDecOp)
         return;
@@ -172,7 +172,7 @@ void CheckAssert::checkVariableAssignment(const Token* assignTok, const Scope *a
     // TODO: function calls on var
 }
 
-bool CheckAssert::inSameScope(const Token* returnTok, const Token* assignTok)
+bool CheckAssertImpl::inSameScope(const Token* returnTok, const Token* assignTok)
 {
     // TODO: even if a return is in the same scope, the assignment might not affect it.
     return returnTok->scope() == assignTok->scope();
@@ -180,13 +180,13 @@ bool CheckAssert::inSameScope(const Token* returnTok, const Token* assignTok)
 
 void CheckAssert::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    CheckAssert checkAssert(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckAssertImpl checkAssert(&tokenizer, &tokenizer.getSettings(), errorLogger);
     checkAssert.assertWithSideEffects();
 }
 
 void CheckAssert::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckAssert c(nullptr, settings, errorLogger);
+    CheckAssertImpl c(nullptr, settings, errorLogger);
     c.sideEffectInAssertError(nullptr, "function");
     c.assignmentInAssertError(nullptr, "var");
 }
diff --git a/lib/checkassert.h b/lib/checkassert.h
index b01831a5eec..3fac8f5af83 100644
--- a/lib/checkassert.h
+++ b/lib/checkassert.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <string>
@@ -42,14 +43,22 @@ class Tokenizer;
 
 class CPPCHECKLIB CheckAssert : public Check {
 public:
-    CheckAssert() : Check(myName()) {}
+    CheckAssert() : Check("Assert") {}
 
 private:
-    CheckAssert(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     /** run checks, the token list is not simplified */
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+
+    std::string classInfo() const override {
+        return "Warn if there are side effects in assert statements (since this cause different behaviour in debug/release builds).\n";
+    }
+};
+
+class CPPCHECKLIB CheckAssertImpl : public CheckImpl {
+public:
+    CheckAssertImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
 
     void assertWithSideEffects();
 
@@ -58,16 +67,6 @@ class CPPCHECKLIB CheckAssert : public Check {
 
     void sideEffectInAssertError(const Token *tok, const std::string& functionName);
     void assignmentInAssertError(const Token *tok, const std::string &varname);
-
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "Assert";
-    }
-
-    std::string classInfo() const override {
-        return "Warn if there are side effects in assert statements (since this cause different behaviour in debug/release builds).\n";
-    }
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp
index fdc5deceefa..0d3cae1c2fa 100644
--- a/lib/checkautovariables.cpp
+++ b/lib/checkautovariables.cpp
@@ -202,7 +202,7 @@ static bool variableIsUsedInScope(const Token* start, nonneg int varId, const Sc
     return false;
 }
 
-void CheckAutoVariables::assignFunctionArg()
+void CheckAutoVariablesImpl::assignFunctionArg()
 {
     const bool printStyle = mSettings->severity.isEnabled(Severity::style);
     const bool printWarning = mSettings->severity.isEnabled(Severity::warning);
@@ -280,7 +280,7 @@ static bool isMemberAssignment(const Token* tok, const Token*& rhs, const Settin
     return true;
 }
 
-void CheckAutoVariables::autoVariables()
+void CheckAutoVariablesImpl::autoVariables()
 {
     logChecker("CheckAutoVariables::autoVariables");
 
@@ -343,7 +343,7 @@ void CheckAutoVariables::autoVariables()
     }
 }
 
-bool CheckAutoVariables::checkAutoVariableAssignment(const Token *expr, bool inconclusive, const Token *startToken)
+bool CheckAutoVariablesImpl::checkAutoVariableAssignment(const Token *expr, bool inconclusive, const Token *startToken)
 {
     if (!startToken)
         startToken = Token::findsimplematch(expr, "=")->next();
@@ -386,7 +386,7 @@ bool CheckAutoVariables::checkAutoVariableAssignment(const Token *expr, bool inc
 
 //---------------------------------------------------------------------------
 
-void CheckAutoVariables::errorAutoVariableAssignment(const Token *tok, bool inconclusive)
+void CheckAutoVariablesImpl::errorAutoVariableAssignment(const Token *tok, bool inconclusive)
 {
     diag(tok);
 
@@ -409,7 +409,7 @@ void CheckAutoVariables::errorAutoVariableAssignment(const Token *tok, bool inco
     }
 }
 
-void CheckAutoVariables::errorUselessAssignmentArg(const Token *tok)
+void CheckAutoVariablesImpl::errorUselessAssignmentArg(const Token *tok)
 {
     reportError(tok,
                 Severity::style,
@@ -417,7 +417,7 @@ void CheckAutoVariables::errorUselessAssignmentArg(const Token *tok)
                 "Assignment of function parameter has no effect outside the function.", CWE398, Certainty::normal);
 }
 
-void CheckAutoVariables::errorUselessAssignmentPtrArg(const Token *tok)
+void CheckAutoVariablesImpl::errorUselessAssignmentPtrArg(const Token *tok)
 {
     reportError(tok,
                 Severity::warning,
@@ -425,7 +425,7 @@ void CheckAutoVariables::errorUselessAssignmentPtrArg(const Token *tok)
                 "Assignment of function parameter has no effect outside the function. Did you forget dereferencing it?", CWE398, Certainty::normal);
 }
 
-bool CheckAutoVariables::diag(const Token* tokvalue)
+bool CheckAutoVariablesImpl::diag(const Token* tokvalue)
 {
     if (!tokvalue)
         return true;
@@ -562,7 +562,7 @@ static bool isAssignedToNonLocal(const Token* tok)
     return !var->isLocal() || var->isStatic();
 }
 
-void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token * end)
+void CheckAutoVariablesImpl::checkVarLifetimeScope(const Token * start, const Token * end)
 {
     const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
     if (!start)
@@ -705,7 +705,7 @@ void CheckAutoVariables::checkVarLifetimeScope(const Token * start, const Token
     }
 }
 
-void CheckAutoVariables::checkVarLifetime()
+void CheckAutoVariablesImpl::checkVarLifetime()
 {
     logChecker("CheckAutoVariables::checkVarLifetime");
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -716,7 +716,7 @@ void CheckAutoVariables::checkVarLifetime()
     }
 }
 
-void CheckAutoVariables::errorReturnDanglingLifetime(const Token *tok, const ValueFlow::Value *val)
+void CheckAutoVariablesImpl::errorReturnDanglingLifetime(const Token *tok, const ValueFlow::Value *val)
 {
     const bool inconclusive = val ? val->isInconclusive() : false;
     ErrorPath errorPath = val ? val->errorPath : ErrorPath();
@@ -725,7 +725,7 @@ void CheckAutoVariables::errorReturnDanglingLifetime(const Token *tok, const Val
     reportError(std::move(errorPath), Severity::error, "returnDanglingLifetime", msg + " that will be invalid when returning.", CWE562, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckAutoVariables::errorInvalidLifetime(const Token *tok, const ValueFlow::Value* val)
+void CheckAutoVariablesImpl::errorInvalidLifetime(const Token *tok, const ValueFlow::Value* val)
 {
     const bool inconclusive = val ? val->isInconclusive() : false;
     ErrorPath errorPath = val ? val->errorPath : ErrorPath();
@@ -734,7 +734,7 @@ void CheckAutoVariables::errorInvalidLifetime(const Token *tok, const ValueFlow:
     reportError(std::move(errorPath), Severity::error, "invalidLifetime", msg + " that is out of scope.", CWE562, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckAutoVariables::errorDanglingTemporaryLifetime(const Token* tok, const ValueFlow::Value* val, const Token* tempTok)
+void CheckAutoVariablesImpl::errorDanglingTemporaryLifetime(const Token* tok, const ValueFlow::Value* val, const Token* tempTok)
 {
     const bool inconclusive = val ? val->isInconclusive() : false;
     ErrorPath errorPath = val ? val->errorPath : ErrorPath();
@@ -749,7 +749,7 @@ void CheckAutoVariables::errorDanglingTemporaryLifetime(const Token* tok, const
                 inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckAutoVariables::errorDanglngLifetime(const Token *tok, const ValueFlow::Value *val, bool isStatic)
+void CheckAutoVariablesImpl::errorDanglngLifetime(const Token *tok, const ValueFlow::Value *val, bool isStatic)
 {
     const bool inconclusive = val ? val->isInconclusive() : false;
     ErrorPath errorPath = val ? val->errorPath : ErrorPath();
@@ -760,21 +760,21 @@ void CheckAutoVariables::errorDanglngLifetime(const Token *tok, const ValueFlow:
     reportError(std::move(errorPath), Severity::error, "danglingLifetime", msg + ".", CWE562, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckAutoVariables::errorDanglingTempReference(const Token* tok, ErrorPath errorPath, bool inconclusive)
+void CheckAutoVariablesImpl::errorDanglingTempReference(const Token* tok, ErrorPath errorPath, bool inconclusive)
 {
     errorPath.emplace_back(tok, "");
     reportError(
         std::move(errorPath), Severity::error, "danglingTempReference", "Using reference to dangling temporary.", CWE562, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckAutoVariables::errorReturnReference(const Token* tok, ErrorPath errorPath, bool inconclusive)
+void CheckAutoVariablesImpl::errorReturnReference(const Token* tok, ErrorPath errorPath, bool inconclusive)
 {
     errorPath.emplace_back(tok, "");
     reportError(
         std::move(errorPath), Severity::error, "returnReference", "Reference to local variable returned.", CWE562, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckAutoVariables::errorDanglingReference(const Token *tok, const Variable *var, ErrorPath errorPath)
+void CheckAutoVariablesImpl::errorDanglingReference(const Token *tok, const Variable *var, ErrorPath errorPath)
 {
     std::string tokName = tok ? tok->str() : "x";
     std::string varName = var ? var->name() : "y";
@@ -783,14 +783,14 @@ void CheckAutoVariables::errorDanglingReference(const Token *tok, const Variable
     reportError(std::move(errorPath), Severity::error, "danglingReference", msg, CWE562, Certainty::normal);
 }
 
-void CheckAutoVariables::errorReturnTempReference(const Token* tok, ErrorPath errorPath, bool inconclusive)
+void CheckAutoVariablesImpl::errorReturnTempReference(const Token* tok, ErrorPath errorPath, bool inconclusive)
 {
     errorPath.emplace_back(tok, "");
     reportError(
         std::move(errorPath), Severity::error, "returnTempReference", "Reference to temporary returned.", CWE562, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckAutoVariables::errorInvalidDeallocation(const Token *tok, const ValueFlow::Value *val)
+void CheckAutoVariablesImpl::errorInvalidDeallocation(const Token *tok, const ValueFlow::Value *val)
 {
     const Variable *var = val ? val->tokvalue->variable() : (tok ? tok->variable() : nullptr);
 
@@ -819,7 +819,7 @@ void CheckAutoVariables::errorInvalidDeallocation(const Token *tok, const ValueF
 
 void CheckAutoVariables::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    CheckAutoVariables checkAutoVariables(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckAutoVariablesImpl checkAutoVariables(&tokenizer, &tokenizer.getSettings(), errorLogger);
     checkAutoVariables.assignFunctionArg();
     checkAutoVariables.autoVariables();
     checkAutoVariables.checkVarLifetime();
@@ -827,7 +827,7 @@ void CheckAutoVariables::runChecks(const Tokenizer &tokenizer, ErrorLogger *erro
 
 void CheckAutoVariables::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckAutoVariables c(nullptr,settings,errorLogger);
+    CheckAutoVariablesImpl c(nullptr,settings,errorLogger);
     c.errorAutoVariableAssignment(nullptr, false);
     c.errorReturnReference(nullptr, ErrorPath{}, false);
     c.errorDanglingReference(nullptr, nullptr, ErrorPath{});
diff --git a/lib/checkautovariables.h b/lib/checkautovariables.h
index d94f254508f..39e6ceb10d5 100644
--- a/lib/checkautovariables.h
+++ b/lib/checkautovariables.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 #include "errortypes.h"
 
@@ -47,16 +48,33 @@ namespace ValueFlow {
 class CPPCHECKLIB CheckAutoVariables : public Check {
 public:
     /** This constructor is used when registering the CheckClass */
-    CheckAutoVariables() : Check(myName()) {}
+    CheckAutoVariables() : Check("Auto Variables") {}
 
 private:
-    /** This constructor is used when running checks. */
-    CheckAutoVariables(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     /** @brief Run checks against the normal token list */
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+
+    std::string classInfo() const override {
+        return "A pointer to a variable is only valid as long as the variable is in scope.\n"
+               "Check:\n"
+               "- returning a pointer to auto or temporary variable\n"
+               "- assigning address of an variable to an effective parameter of a function\n"
+               "- returning reference to local/temporary variable\n"
+               "- returning address of function parameter\n"
+               "- suspicious assignment of pointer argument\n"
+               "- useless assignment of function argument\n";
+    }
+};
+
+class CPPCHECKLIB CheckAutoVariablesImpl : public CheckImpl
+{
+public:
+    /** This constructor is used when running checks. */
+    CheckAutoVariablesImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     /** assign function argument */
     void assignFunctionArg();
 
@@ -69,7 +87,6 @@ class CPPCHECKLIB CheckAutoVariables : public Check {
     bool checkAutoVariableAssignment(const Token *expr, bool inconclusive, const Token *startToken = nullptr);
 
     void checkVarLifetime();
-
     void checkVarLifetimeScope(const Token * start, const Token * end);
 
     void errorAutoVariableAssignment(const Token *tok, bool inconclusive);
@@ -85,24 +102,8 @@ class CPPCHECKLIB CheckAutoVariables : public Check {
     void errorUselessAssignmentArg(const Token *tok);
     void errorUselessAssignmentPtrArg(const Token *tok);
 
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "Auto Variables";
-    }
-
-    std::string classInfo() const override {
-        return "A pointer to a variable is only valid as long as the variable is in scope.\n"
-               "Check:\n"
-               "- returning a pointer to auto or temporary variable\n"
-               "- assigning address of an variable to an effective parameter of a function\n"
-               "- returning reference to local/temporary variable\n"
-               "- returning address of function parameter\n"
-               "- suspicious assignment of pointer argument\n"
-               "- useless assignment of function argument\n";
-    }
-
     /** returns true if tokvalue has already been diagnosed */
+private:
     bool diag(const Token* tokvalue);
 
     std::set<const Token*> mDiagDanglingTemp;
diff --git a/lib/checkbool.cpp b/lib/checkbool.cpp
index c9a66876317..e4f55f26085 100644
--- a/lib/checkbool.cpp
+++ b/lib/checkbool.cpp
@@ -43,7 +43,7 @@ static bool isBool(const Variable* var)
 }
 
 //---------------------------------------------------------------------------
-void CheckBool::checkIncrementBoolean()
+void CheckBoolImpl::checkIncrementBoolean()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("incrementboolean"))
         return;
@@ -60,7 +60,7 @@ void CheckBool::checkIncrementBoolean()
     }
 }
 
-void CheckBool::incrementBooleanError(const Token *tok)
+void CheckBoolImpl::incrementBooleanError(const Token *tok)
 {
     reportError(
         tok,
@@ -83,7 +83,7 @@ static bool isConvertedToBool(const Token* tok)
 // if (bool & bool) -> if (bool && bool)
 // if (bool | bool) -> if (bool || bool)
 //---------------------------------------------------------------------------
-void CheckBool::checkBitwiseOnBoolean()
+void CheckBoolImpl::checkBitwiseOnBoolean()
 {
     if (!mSettings->isPremiumEnabled("bitwiseOnBoolean") &&
         !mSettings->severity.isEnabled(Severity::style) &&
@@ -127,7 +127,7 @@ void CheckBool::checkBitwiseOnBoolean()
     }
 }
 
-void CheckBool::bitwiseOnBooleanError(const Token* tok, const std::string& expression, const std::string& op, bool isCompound)
+void CheckBoolImpl::bitwiseOnBooleanError(const Token* tok, const std::string& expression, const std::string& op, bool isCompound)
 {
     std::string msg = "Boolean expression '" + expression + "' is used in bitwise operation.";
     if (!isCompound)
@@ -144,7 +144,7 @@ void CheckBool::bitwiseOnBooleanError(const Token* tok, const std::string& expre
 //    if (!x==3) <- Probably meant to be "x!=3"
 //---------------------------------------------------------------------------
 
-void CheckBool::checkComparisonOfBoolWithInt()
+void CheckBoolImpl::checkComparisonOfBoolWithInt()
 {
     if (!mSettings->severity.isEnabled(Severity::warning) || !mTokenizer->isCPP())
         return;
@@ -171,7 +171,7 @@ void CheckBool::checkComparisonOfBoolWithInt()
     }
 }
 
-void CheckBool::comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression)
+void CheckBoolImpl::comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression)
 {
     reportError(tok, Severity::warning, "comparisonOfBoolWithInvalidComparator",
                 "Comparison of a boolean value using relational operator (<, >, <= or >=).\n"
@@ -195,7 +195,7 @@ static bool tokenIsFunctionReturningBool(const Token* tok)
     return false;
 }
 
-void CheckBool::checkComparisonOfFuncReturningBool()
+void CheckBoolImpl::checkComparisonOfFuncReturningBool()
 {
     if (!mSettings->severity.isEnabled(Severity::style))
         return;
@@ -239,7 +239,7 @@ void CheckBool::checkComparisonOfFuncReturningBool()
     }
 }
 
-void CheckBool::comparisonOfFuncReturningBoolError(const Token *tok, const std::string &expression)
+void CheckBoolImpl::comparisonOfFuncReturningBoolError(const Token *tok, const std::string &expression)
 {
     reportError(tok, Severity::style, "comparisonOfFuncReturningBoolError",
                 "Comparison of a function returning boolean value using relational (<, >, <= or >=) operator.\n"
@@ -248,7 +248,7 @@ void CheckBool::comparisonOfFuncReturningBoolError(const Token *tok, const std::
                 " operator could cause unexpected results.", CWE398, Certainty::normal);
 }
 
-void CheckBool::comparisonOfTwoFuncsReturningBoolError(const Token *tok, const std::string &expression1, const std::string &expression2)
+void CheckBoolImpl::comparisonOfTwoFuncsReturningBoolError(const Token *tok, const std::string &expression1, const std::string &expression2)
 {
     reportError(tok, Severity::style, "comparisonOfTwoFuncsReturningBoolError",
                 "Comparison of two functions returning boolean value using relational (<, >, <= or >=) operator.\n"
@@ -261,7 +261,7 @@ void CheckBool::comparisonOfTwoFuncsReturningBoolError(const Token *tok, const s
 // Comparison of bool with bool
 //-------------------------------------------------------------------------------
 
-void CheckBool::checkComparisonOfBoolWithBool()
+void CheckBoolImpl::checkComparisonOfBoolWithBool()
 {
     if (!mSettings->severity.isEnabled(Severity::style))
         return;
@@ -302,7 +302,7 @@ void CheckBool::checkComparisonOfBoolWithBool()
     }
 }
 
-void CheckBool::comparisonOfBoolWithBoolError(const Token *tok, const std::string &expression)
+void CheckBoolImpl::comparisonOfBoolWithBoolError(const Token *tok, const std::string &expression)
 {
     reportError(tok, Severity::style, "comparisonOfBoolWithBoolError",
                 "Comparison of a variable having boolean value using relational (<, >, <= or >=) operator.\n"
@@ -312,7 +312,7 @@ void CheckBool::comparisonOfBoolWithBoolError(const Token *tok, const std::strin
 }
 
 //-----------------------------------------------------------------------------
-void CheckBool::checkAssignBoolToPointer()
+void CheckBoolImpl::checkAssignBoolToPointer()
 {
     logChecker("CheckBool::checkAssignBoolToPointer");
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -325,7 +325,7 @@ void CheckBool::checkAssignBoolToPointer()
     }
 }
 
-void CheckBool::assignBoolToPointerError(const Token *tok)
+void CheckBoolImpl::assignBoolToPointerError(const Token *tok)
 {
     reportError(tok, Severity::error, "assignBoolToPointer",
                 "Boolean value assigned to pointer.", CWE587, Certainty::normal);
@@ -333,7 +333,7 @@ void CheckBool::assignBoolToPointerError(const Token *tok)
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
-void CheckBool::checkComparisonOfBoolExpressionWithInt()
+void CheckBoolImpl::checkComparisonOfBoolExpressionWithInt()
 {
     if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("compareBoolExpressionWithInt"))
         return;
@@ -393,7 +393,7 @@ void CheckBool::checkComparisonOfBoolExpressionWithInt()
     }
 }
 
-void CheckBool::comparisonOfBoolExpressionWithIntError(const Token *tok, bool not0or1)
+void CheckBoolImpl::comparisonOfBoolExpressionWithIntError(const Token *tok, bool not0or1)
 {
     if (not0or1)
         reportError(tok, Severity::warning, "compareBoolExpressionWithInt",
@@ -404,7 +404,7 @@ void CheckBool::comparisonOfBoolExpressionWithIntError(const Token *tok, bool no
 }
 
 
-void CheckBool::pointerArithBool()
+void CheckBoolImpl::pointerArithBool()
 {
     logChecker("CheckBool::pointerArithBool");
 
@@ -427,7 +427,7 @@ void CheckBool::pointerArithBool()
     }
 }
 
-void CheckBool::pointerArithBoolCond(const Token *tok)
+void CheckBoolImpl::pointerArithBoolCond(const Token *tok)
 {
     if (!tok)
         return;
@@ -447,7 +447,7 @@ void CheckBool::pointerArithBoolCond(const Token *tok)
         pointerArithBoolError(tok);
 }
 
-void CheckBool::pointerArithBoolError(const Token *tok)
+void CheckBoolImpl::pointerArithBoolError(const Token *tok)
 {
     reportError(tok,
                 Severity::error,
@@ -456,7 +456,7 @@ void CheckBool::pointerArithBoolError(const Token *tok)
                 "Converting pointer arithmetic result to bool. The boolean result is always true unless there is pointer arithmetic overflow, and overflow is undefined behaviour. Probably a dereference is forgotten.", CWE571, Certainty::normal);
 }
 
-void CheckBool::checkAssignBoolToFloat()
+void CheckBoolImpl::checkAssignBoolToFloat()
 {
     if (!mTokenizer->isCPP())
         return;
@@ -473,13 +473,13 @@ void CheckBool::checkAssignBoolToFloat()
     }
 }
 
-void CheckBool::assignBoolToFloatError(const Token *tok)
+void CheckBoolImpl::assignBoolToFloatError(const Token *tok)
 {
     reportError(tok, Severity::style, "assignBoolToFloat",
                 "Boolean value assigned to floating point variable.", CWE704, Certainty::normal);
 }
 
-void CheckBool::returnValueOfFunctionReturningBool()
+void CheckBoolImpl::returnValueOfFunctionReturningBool()
 {
     if (!mSettings->severity.isEnabled(Severity::style))
         return;
@@ -507,14 +507,14 @@ void CheckBool::returnValueOfFunctionReturningBool()
     }
 }
 
-void CheckBool::returnValueBoolError(const Token *tok)
+void CheckBoolImpl::returnValueBoolError(const Token *tok)
 {
     reportError(tok, Severity::style, "returnNonBoolInBooleanFunction", "Non-boolean value returned from function returning bool");
 }
 
 void CheckBool::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    CheckBool checkBool(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckBoolImpl checkBool(&tokenizer, &tokenizer.getSettings(), errorLogger);
 
     // Checks
     checkBool.checkComparisonOfBoolExpressionWithInt();
@@ -531,7 +531,7 @@ void CheckBool::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 
 void CheckBool::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckBool c(nullptr, settings, errorLogger);
+    CheckBoolImpl c(nullptr, settings, errorLogger);
     c.assignBoolToPointerError(nullptr);
     c.assignBoolToFloatError(nullptr);
     c.comparisonOfFuncReturningBoolError(nullptr, "func_name");
diff --git a/lib/checkbool.h b/lib/checkbool.h
index 65e5d0254ea..607d9c4a4b7 100644
--- a/lib/checkbool.h
+++ b/lib/checkbool.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <string>
@@ -41,16 +42,34 @@ class Tokenizer;
 class CPPCHECKLIB CheckBool : public Check {
 public:
     /** @brief This constructor is used when registering the CheckClass */
-    CheckBool() : Check(myName()) {}
+    CheckBool() : Check("Boolean") {}
 
 private:
-    /** @brief This constructor is used when running checks. */
-    CheckBool(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     /** @brief Run checks against the normal token list */
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+
+    std::string classInfo() const override {
+        return "Boolean type checks\n"
+               "- using increment on boolean\n"
+               "- comparison of a boolean expression with an integer other than 0 or 1\n"
+               "- comparison of a function returning boolean value using relational operator\n"
+               "- comparison of a boolean value with boolean value using relational operator\n"
+               "- using bool in bitwise expression\n"
+               "- pointer addition in condition (either dereference is forgot or pointer overflow is required to make the condition false)\n"
+               "- Assigning bool value to pointer or float\n"
+               "- Returning an integer other than 0 or 1 from a function with boolean return value\n";
+    }
+};
+
+class CPPCHECKLIB CheckBoolImpl : public CheckImpl
+{
+public:
+    /** @brief This constructor is used when running checks. */
+    CheckBoolImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     /** @brief %Check for comparison of function returning bool*/
     void checkComparisonOfFuncReturningBool();
 
@@ -94,24 +113,6 @@ class CPPCHECKLIB CheckBool : public Check {
     void comparisonOfBoolExpressionWithIntError(const Token *tok, bool not0or1);
     void pointerArithBoolError(const Token *tok);
     void returnValueBoolError(const Token *tok);
-
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "Boolean";
-    }
-
-    std::string classInfo() const override {
-        return "Boolean type checks\n"
-               "- using increment on boolean\n"
-               "- comparison of a boolean expression with an integer other than 0 or 1\n"
-               "- comparison of a function returning boolean value using relational operator\n"
-               "- comparison of a boolean value with boolean value using relational operator\n"
-               "- using bool in bitwise expression\n"
-               "- pointer addition in condition (either dereference is forgot or pointer overflow is required to make the condition false)\n"
-               "- Assigning bool value to pointer or float\n"
-               "- Returning an integer other than 0 or 1 from a function with boolean return value\n";
-    }
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp
index 3ba41882316..77905fcc473 100644
--- a/lib/checkbufferoverrun.cpp
+++ b/lib/checkbufferoverrun.cpp
@@ -284,7 +284,7 @@ static std::vector<ValueFlow::Value> getOverrunIndexValues(const Token* tok,
     return {};
 }
 
-void CheckBufferOverrun::arrayIndex()
+void CheckBufferOverrunImpl::arrayIndex()
 {
     logChecker("CheckBufferOverrun::arrayIndex");
 
@@ -405,9 +405,9 @@ static std::string arrayIndexMessage(const Token* tok,
     return errmsg.str();
 }
 
-void CheckBufferOverrun::arrayIndexError(const Token* tok,
-                                         const std::vector<Dimension>& dimensions,
-                                         const std::vector<ValueFlow::Value>& indexes)
+void CheckBufferOverrunImpl::arrayIndexError(const Token* tok,
+                                             const std::vector<Dimension>& dimensions,
+                                             const std::vector<ValueFlow::Value>& indexes)
 {
     if (!tok) {
         reportError(tok, Severity::error, "arrayIndexOutOfBounds", "Array 'arr[16]' accessed at index 16, which is out of bounds.", CWE_BUFFER_OVERRUN, Certainty::normal);
@@ -434,7 +434,7 @@ void CheckBufferOverrun::arrayIndexError(const Token* tok,
                 index->isInconclusive() ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckBufferOverrun::negativeIndexError(const Token* tok,
+void CheckBufferOverrunImpl::negativeIndexError(const Token* tok,
                                             const std::vector<Dimension>& dimensions,
                                             const std::vector<ValueFlow::Value>& indexes)
 {
@@ -464,7 +464,7 @@ void CheckBufferOverrun::negativeIndexError(const Token* tok,
 
 //---------------------------------------------------------------------------
 
-void CheckBufferOverrun::pointerArithmetic()
+void CheckBufferOverrunImpl::pointerArithmetic()
 {
     if (!mSettings->severity.isEnabled(Severity::portability) && !mSettings->isPremiumEnabled("pointerOutOfBounds"))
         return;
@@ -528,7 +528,7 @@ void CheckBufferOverrun::pointerArithmetic()
     }
 }
 
-void CheckBufferOverrun::pointerArithmeticError(const Token *tok, const Token *indexToken, const ValueFlow::Value *indexValue)
+void CheckBufferOverrunImpl::pointerArithmeticError(const Token *tok, const Token *indexToken, const ValueFlow::Value *indexValue)
 {
     if (!tok) {
         reportError(tok, Severity::portability, "pointerOutOfBounds", "Pointer arithmetic overflow.", CWE_POINTER_ARITHMETIC_OVERFLOW, Certainty::normal);
@@ -552,7 +552,7 @@ void CheckBufferOverrun::pointerArithmeticError(const Token *tok, const Token *i
 
 //---------------------------------------------------------------------------
 
-ValueFlow::Value CheckBufferOverrun::getBufferSize(const Token *bufTok) const
+ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok) const
 {
     if (!bufTok->valueType())
         return ValueFlow::Value(-1);
@@ -634,7 +634,7 @@ static bool checkBufferSize(const Token *ftok, const Library::ArgumentChecks::Mi
 }
 
 
-void CheckBufferOverrun::bufferOverflow()
+void CheckBufferOverrunImpl::bufferOverflow()
 {
     logChecker("CheckBufferOverrun::bufferOverflow");
 
@@ -691,14 +691,14 @@ void CheckBufferOverrun::bufferOverflow()
     }
 }
 
-void CheckBufferOverrun::bufferOverflowError(const Token *tok, const ValueFlow::Value *value, Certainty certainty)
+void CheckBufferOverrunImpl::bufferOverflowError(const Token *tok, const ValueFlow::Value *value, Certainty certainty)
 {
     reportError(getErrorPath(tok, value, "Buffer overrun"), Severity::error, "bufferAccessOutOfBounds", "Buffer is accessed out of bounds: " + (tok ? getRealBufferTok(tok)->expressionString() : "buf"), CWE_BUFFER_OVERRUN, certainty);
 }
 
 //---------------------------------------------------------------------------
 
-void CheckBufferOverrun::arrayIndexThenCheck()
+void CheckBufferOverrunImpl::arrayIndexThenCheck()
 {
     if (!mSettings->severity.isEnabled(Severity::style))
         return;
@@ -742,7 +742,7 @@ void CheckBufferOverrun::arrayIndexThenCheck()
     }
 }
 
-void CheckBufferOverrun::arrayIndexThenCheckError(const Token *tok, const std::string &indexName)
+void CheckBufferOverrunImpl::arrayIndexThenCheckError(const Token *tok, const std::string &indexName)
 {
     reportError(tok, Severity::style, "arrayIndexThenCheck",
                 "$symbol:" + indexName + "\n"
@@ -755,7 +755,7 @@ void CheckBufferOverrun::arrayIndexThenCheckError(const Token *tok, const std::s
 
 //---------------------------------------------------------------------------
 
-void CheckBufferOverrun::stringNotZeroTerminated()
+void CheckBufferOverrunImpl::stringNotZeroTerminated()
 {
     // this is currently 'inconclusive'. See TestBufferOverrun::terminateStrncpy3
     if (!mSettings->severity.isEnabled(Severity::warning) || !mSettings->certainty.isEnabled(Certainty::inconclusive))
@@ -808,7 +808,7 @@ void CheckBufferOverrun::stringNotZeroTerminated()
     }
 }
 
-void CheckBufferOverrun::terminateStrncpyError(const Token *tok, const std::string &varname)
+void CheckBufferOverrunImpl::terminateStrncpyError(const Token *tok, const std::string &varname)
 {
     const std::string shortMessage = "The buffer '$symbol' may not be null-terminated after the call to strncpy().";
     reportError(tok, Severity::warning, "terminateStrncpy",
@@ -821,7 +821,7 @@ void CheckBufferOverrun::terminateStrncpyError(const Token *tok, const std::stri
 }
 //---------------------------------------------------------------------------
 
-void CheckBufferOverrun::argumentSize()
+void CheckBufferOverrunImpl::argumentSize()
 {
     // Check '%type% x[10]' arguments
     if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("argumentSize"))
@@ -869,7 +869,7 @@ void CheckBufferOverrun::argumentSize()
     }
 }
 
-void CheckBufferOverrun::argumentSizeError(const Token *tok, const std::string &functionName, nonneg int paramIndex, const std::string &paramExpression, const Variable *paramVar, const Variable *functionArg)
+void CheckBufferOverrunImpl::argumentSizeError(const Token *tok, const std::string &functionName, nonneg int paramIndex, const std::string &paramExpression, const Variable *paramVar, const Variable *functionArg)
 {
     const std::string strParamNum = std::to_string(paramIndex + 1) + getOrdinalText(paramIndex + 1);
     ErrorPath errorPath;
@@ -920,7 +920,7 @@ namespace
     };
 }
 
-bool CheckBufferOverrun::isCtuUnsafeBufferUsage(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset, int type)
+bool CheckBufferOverrunImpl::isCtuUnsafeBufferUsage(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset, int type)
 {
     if (!offset)
         return false;
@@ -941,12 +941,12 @@ bool CheckBufferOverrun::isCtuUnsafeBufferUsage(const Settings &settings, const
     return true;
 }
 
-bool CheckBufferOverrun::isCtuUnsafeArrayIndex(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset)
+bool CheckBufferOverrunImpl::isCtuUnsafeArrayIndex(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset)
 {
     return isCtuUnsafeBufferUsage(settings, argtok, offset, 1);
 }
 
-bool CheckBufferOverrun::isCtuUnsafePointerArith(const Settings &settings, const Token *argtok, CTU::FileInfo::Value* offset)
+bool CheckBufferOverrunImpl::isCtuUnsafePointerArith(const Settings &settings, const Token *argtok, CTU::FileInfo::Value* offset)
 {
     return isCtuUnsafeBufferUsage(settings, argtok, offset, 2);
 }
@@ -954,8 +954,8 @@ bool CheckBufferOverrun::isCtuUnsafePointerArith(const Settings &settings, const
 /** @brief Parse current TU and extract file info */
 Check::FileInfo *CheckBufferOverrun::getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& /*currentConfig*/) const
 {
-    const std::list<CTU::FileInfo::UnsafeUsage> &unsafeArrayIndex = CTU::getUnsafeUsage(tokenizer, settings, isCtuUnsafeArrayIndex);
-    const std::list<CTU::FileInfo::UnsafeUsage> &unsafePointerArith = CTU::getUnsafeUsage(tokenizer, settings, isCtuUnsafePointerArith);
+    const std::list<CTU::FileInfo::UnsafeUsage> &unsafeArrayIndex = CTU::getUnsafeUsage(tokenizer, settings, CheckBufferOverrunImpl::isCtuUnsafeArrayIndex);
+    const std::list<CTU::FileInfo::UnsafeUsage> &unsafePointerArith = CTU::getUnsafeUsage(tokenizer, settings, CheckBufferOverrunImpl::isCtuUnsafePointerArith);
     if (unsafeArrayIndex.empty() && unsafePointerArith.empty()) {
         return nullptr;
     }
@@ -967,7 +967,6 @@ Check::FileInfo *CheckBufferOverrun::getFileInfo(const Tokenizer &tokenizer, con
 
 Check::FileInfo * CheckBufferOverrun::loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const
 {
-    // cppcheck-suppress shadowFunction - TODO: fix this
     const std::string arrayIndex("array-index");
     const std::string pointerArith("pointer-arith");
 
@@ -991,7 +990,7 @@ Check::FileInfo * CheckBufferOverrun::loadFileInfoFromXml(const tinyxml2::XMLEle
 /** @brief Analyse all file infos for all TU */
 bool CheckBufferOverrun::analyseWholeProgram(const CTU::FileInfo &ctu, const std::list<Check::FileInfo*> &fileInfo, const Settings& settings, ErrorLogger &errorLogger)
 {
-    CheckBufferOverrun dummy(nullptr, &settings, &errorLogger);
+    CheckBufferOverrunImpl dummy(nullptr, &settings, &errorLogger);
     dummy.
     logChecker("CheckBufferOverrun::analyseWholeProgram");
 
@@ -1058,7 +1057,7 @@ bool CheckBufferOverrun::analyseWholeProgram1(const std::map<std::string, std::l
     return true;
 }
 
-void CheckBufferOverrun::objectIndex()
+void CheckBufferOverrunImpl::objectIndex()
 {
     logChecker("CheckBufferOverrun::objectIndex");
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -1130,7 +1129,7 @@ void CheckBufferOverrun::objectIndex()
     }
 }
 
-void CheckBufferOverrun::objectIndexError(const Token *tok, const ValueFlow::Value *v, bool known)
+void CheckBufferOverrunImpl::objectIndexError(const Token *tok, const ValueFlow::Value *v, bool known)
 {
     ErrorPath errorPath;
     std::string name;
@@ -1167,7 +1166,7 @@ static bool isVLAIndex(const Token* tok)
     return isVLAIndex(tok->astOperand1()) || isVLAIndex(tok->astOperand2());
 }
 
-void CheckBufferOverrun::negativeArraySize()
+void CheckBufferOverrunImpl::negativeArraySize()
 {
     logChecker("CheckBufferOverrun::negativeArraySize");
     const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -1197,7 +1196,7 @@ void CheckBufferOverrun::negativeArraySize()
     }
 }
 
-void CheckBufferOverrun::negativeArraySizeError(const Token* tok)
+void CheckBufferOverrunImpl::negativeArraySizeError(const Token* tok)
 {
     const std::string arrayName = tok ? tok->expressionString() : std::string();
     const std::string line1 = arrayName.empty() ? std::string() : ("$symbol:" + arrayName + '\n');
@@ -1206,7 +1205,7 @@ void CheckBufferOverrun::negativeArraySizeError(const Token* tok)
                 "Declaration of array '" + arrayName + "' with negative size is undefined behaviour", CWE758, Certainty::normal);
 }
 
-void CheckBufferOverrun::negativeMemoryAllocationSizeError(const Token* tok, const ValueFlow::Value* value)
+void CheckBufferOverrunImpl::negativeMemoryAllocationSizeError(const Token* tok, const ValueFlow::Value* value)
 {
     const std::string msg = "Memory allocation size is negative.";
     ErrorPath errorPath = getErrorPath(tok, value, msg);
@@ -1217,7 +1216,7 @@ void CheckBufferOverrun::negativeMemoryAllocationSizeError(const Token* tok, con
 
 void CheckBufferOverrun::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    CheckBufferOverrun checkBufferOverrun(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckBufferOverrunImpl checkBufferOverrun(&tokenizer, &tokenizer.getSettings(), errorLogger);
     checkBufferOverrun.arrayIndex();
     checkBufferOverrun.pointerArithmetic();
     checkBufferOverrun.bufferOverflow();
@@ -1230,7 +1229,7 @@ void CheckBufferOverrun::runChecks(const Tokenizer &tokenizer, ErrorLogger *erro
 
 void CheckBufferOverrun::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckBufferOverrun c(nullptr, settings, errorLogger);
+    CheckBufferOverrunImpl c(nullptr, settings, errorLogger);
     c.arrayIndexError(nullptr, std::vector<Dimension>(), std::vector<ValueFlow::Value>());
     c.pointerArithmeticError(nullptr, nullptr, nullptr);
     c.negativeIndexError(nullptr, std::vector<Dimension>(), std::vector<ValueFlow::Value>());
diff --git a/lib/checkbufferoverrun.h b/lib/checkbufferoverrun.h
index 9c6e1f0386d..fdf47121bb8 100644
--- a/lib/checkbufferoverrun.h
+++ b/lib/checkbufferoverrun.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 #include "ctu.h"
 
@@ -60,23 +61,44 @@ namespace ValueFlow
 class CPPCHECKLIB CheckBufferOverrun : public Check {
 public:
     /** This constructor is used when registering the CheckClass */
-    CheckBufferOverrun() : Check(myName()) {}
+    CheckBufferOverrun() : Check("Bounds checking") {}
 
 private:
-    /** This constructor is used when running checks. */
-    CheckBufferOverrun(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
     /** @brief Parse current TU and extract file info */
     Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& /*currentConfig*/) const override;
 
     /** @brief Analyse all file infos for all TU */
     bool analyseWholeProgram(const CTU::FileInfo &ctu, const std::list<Check::FileInfo*> &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override;
 
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+
+    Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override;
+
+    std::string classInfo() const override {
+        return "Out of bounds checking:\n"
+               "- Array index out of bounds\n"
+               "- Pointer arithmetic overflow\n"
+               "- Buffer overflow\n"
+               "- Dangerous usage of strncat()\n"
+               "- Using array index before checking it\n"
+               "- Partial string write that leads to buffer that is not zero terminated.\n"
+               "- Check for large enough arrays being passed to functions\n"
+               "- Allocating memory with a negative size\n";
+    }
+
+    static bool analyseWholeProgram1(const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> &callsMap, const CTU::FileInfo::UnsafeUsage &unsafeUsage,
+                                     int type, ErrorLogger &errorLogger, int maxCtuDepth, const std::string& file0);
+};
+
+class CPPCHECKLIB CheckBufferOverrunImpl : public CheckImpl
+{
+public:
+    /** This constructor is used when running checks. */
+    CheckBufferOverrunImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     void arrayIndex();
     void arrayIndexError(const Token* tok,
                          const std::vector<Dimension>& dimensions,
@@ -113,27 +135,6 @@ class CPPCHECKLIB CheckBufferOverrun : public Check {
     static bool isCtuUnsafeBufferUsage(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset, int type);
     static bool isCtuUnsafeArrayIndex(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset);
     static bool isCtuUnsafePointerArith(const Settings &settings, const Token *argtok, CTU::FileInfo::Value *offset);
-
-    Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override;
-    static bool analyseWholeProgram1(const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> &callsMap, const CTU::FileInfo::UnsafeUsage &unsafeUsage,
-                                     int type, ErrorLogger &errorLogger, int maxCtuDepth, const std::string& file0);
-
-
-    static std::string myName() {
-        return "Bounds checking";
-    }
-
-    std::string classInfo() const override {
-        return "Out of bounds checking:\n"
-               "- Array index out of bounds\n"
-               "- Pointer arithmetic overflow\n"
-               "- Buffer overflow\n"
-               "- Dangerous usage of strncat()\n"
-               "- Using array index before checking it\n"
-               "- Partial string write that leads to buffer that is not zero terminated.\n"
-               "- Check for large enough arrays being passed to functions\n"
-               "- Allocating memory with a negative size\n";
-    }
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp
index 3313fb636ed..94cafaab3ae 100644
--- a/lib/checkclass.cpp
+++ b/lib/checkclass.cpp
@@ -106,12 +106,12 @@ static bool isVclTypeInit(const Type *type)
 }
 //---------------------------------------------------------------------------
 
-CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-    : Check(myName(), tokenizer, settings, errorLogger),
+CheckClassImpl::CheckClassImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+    : CheckImpl(tokenizer, settings, errorLogger),
     mSymbolDatabase(tokenizer?tokenizer->getSymbolDatabase():nullptr)
 {}
 
-bool CheckClass::isInitialized(const CheckClass::Usage& usage, FunctionType funcType) const
+bool CheckClassImpl::isInitialized(const Usage& usage, FunctionType funcType) const
 {
     const Variable& var = *usage.var;
 
@@ -170,7 +170,7 @@ bool CheckClass::isInitialized(const CheckClass::Usage& usage, FunctionType func
     return false;
 }
 
-void CheckClass::handleUnionMembers(std::vector<Usage>& usageList)
+void CheckClassImpl::handleUnionMembers(std::vector<Usage>& usageList)
 {
     // Assign 1 union member => assign all union members
     for (const Usage& usage : usageList) {
@@ -199,7 +199,7 @@ void CheckClass::handleUnionMembers(std::vector<Usage>& usageList)
 // ClassCheck: Check that all class constructors are ok.
 //---------------------------------------------------------------------------
 
-void CheckClass::constructors()
+void CheckClassImpl::constructors()
 {
     const bool printStyle = mSettings->severity.isEnabled(Severity::style);
     const bool printWarnings = mSettings->severity.isEnabled(Severity::warning);
@@ -385,7 +385,7 @@ static bool isPermissibleConversion(const std::string& type)
     return type == "std::initializer_list" || type == "std::nullptr_t";
 }
 
-void CheckClass::checkExplicitConstructors()
+void CheckClassImpl::checkExplicitConstructors()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("noExplicitConstructor"))
         return;
@@ -454,7 +454,7 @@ static bool hasNonCopyableBase(const Scope *scope, bool *unknown)
     return false;
 }
 
-void CheckClass::copyconstructors()
+void CheckClassImpl::copyconstructors()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -611,7 +611,7 @@ void CheckClass::copyconstructors()
    }
  */
 
-void CheckClass::copyConstructorShallowCopyError(const Token *tok, const std::string& varname)
+void CheckClassImpl::copyConstructorShallowCopyError(const Token *tok, const std::string& varname)
 {
     reportError(tok, Severity::warning, "copyCtorPointerCopying",
                 "$symbol:" + varname + "\nValue of pointer '$symbol', which points to allocated memory, is copied in copy constructor instead of allocating new memory.", CWE398, Certainty::normal);
@@ -637,22 +637,22 @@ static std::string noMemberErrorMessage(const Scope *scope, const char function[
     return errmsg;
 }
 
-void CheckClass::noCopyConstructorError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive)
+void CheckClassImpl::noCopyConstructorError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive)
 {
     reportError(alloc, Severity::warning, "noCopyConstructor", noMemberErrorMessage(scope, "copy constructor", isdefault), CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckClass::noOperatorEqError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive)
+void CheckClassImpl::noOperatorEqError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive)
 {
     reportError(alloc, Severity::warning, "noOperatorEq", noMemberErrorMessage(scope, "operator=", isdefault), CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckClass::noDestructorError(const Scope *scope, bool isdefault, const Token *alloc)
+void CheckClassImpl::noDestructorError(const Scope *scope, bool isdefault, const Token *alloc)
 {
     reportError(alloc, Severity::warning, "noDestructor", noMemberErrorMessage(scope, "destructor", isdefault), CWE398, Certainty::normal);
 }
 
-bool CheckClass::canNotCopy(const Scope *scope)
+bool CheckClassImpl::canNotCopy(const Scope *scope)
 {
     bool constructor = false;
     bool publicAssign = false;
@@ -676,7 +676,7 @@ bool CheckClass::canNotCopy(const Scope *scope)
     return constructor && !(publicAssign || publicCopy);
 }
 
-bool CheckClass::canNotMove(const Scope *scope)
+bool CheckClassImpl::canNotMove(const Scope *scope)
 {
     bool constructor = false;
     bool publicAssign = false;
@@ -721,7 +721,7 @@ static void getAllVariableMembers(const Scope *scope, std::vector<const Variable
     }
 }
 
-std::vector<CheckClass::Usage> CheckClass::createUsageList(const Scope *scope)
+std::vector<CheckClassImpl::Usage> CheckClassImpl::createUsageList(const Scope *scope)
 {
     std::vector<Usage> ret;
     std::vector<const Variable *> varlist;
@@ -733,7 +733,7 @@ std::vector<CheckClass::Usage> CheckClass::createUsageList(const Scope *scope)
     return ret;
 }
 
-void CheckClass::assignVar(std::vector<Usage> &usageList, nonneg int varid)
+void CheckClassImpl::assignVar(std::vector<Usage> &usageList, nonneg int varid)
 {
     auto it = std::find_if(usageList.begin(), usageList.end(), [varid](const Usage& usage) {
         return usage.var->declarationId() == varid;
@@ -742,7 +742,7 @@ void CheckClass::assignVar(std::vector<Usage> &usageList, nonneg int varid)
         it->assign = true;
 }
 
-void CheckClass::assignVar(std::vector<Usage> &usageList, const Token* vartok)
+void CheckClassImpl::assignVar(std::vector<Usage> &usageList, const Token* vartok)
 {
     if (vartok->varId() > 0) {
         assignVar(usageList, vartok->varId());
@@ -756,7 +756,7 @@ void CheckClass::assignVar(std::vector<Usage> &usageList, const Token* vartok)
         it->assign = true;
 }
 
-void CheckClass::initVar(std::vector<Usage> &usageList, nonneg int varid)
+void CheckClassImpl::initVar(std::vector<Usage> &usageList, nonneg int varid)
 {
     auto it = std::find_if(usageList.begin(), usageList.end(), [varid](const Usage& usage) {
         return usage.var->declarationId() == varid;
@@ -765,13 +765,13 @@ void CheckClass::initVar(std::vector<Usage> &usageList, nonneg int varid)
         it->init = true;
 }
 
-void CheckClass::assignAllVar(std::vector<Usage> &usageList)
+void CheckClassImpl::assignAllVar(std::vector<Usage> &usageList)
 {
     for (Usage & i : usageList)
         i.assign = true;
 }
 
-void CheckClass::assignAllVarsVisibleFromScope(std::vector<Usage>& usageList, const Scope* scope)
+void CheckClassImpl::assignAllVarsVisibleFromScope(std::vector<Usage>& usageList, const Scope* scope)
 {
     for (Usage& usage : usageList) {
         if (usage.var->scope() == scope)
@@ -787,7 +787,7 @@ void CheckClass::assignAllVarsVisibleFromScope(std::vector<Usage>& usageList, co
     }
 }
 
-void CheckClass::clearAllVar(std::vector<Usage> &usageList)
+void CheckClassImpl::clearAllVar(std::vector<Usage> &usageList)
 {
     for (Usage & i : usageList) {
         i.assign = false;
@@ -795,7 +795,7 @@ void CheckClass::clearAllVar(std::vector<Usage> &usageList)
     }
 }
 
-bool CheckClass::isBaseClassMutableMemberFunc(const Token *tok, const Scope *scope)
+bool CheckClassImpl::isBaseClassMutableMemberFunc(const Token *tok, const Scope *scope)
 {
     // Iterate through each base class...
     for (const Type::BaseInfo & i : scope->definedType->derivedFrom) {
@@ -822,7 +822,7 @@ bool CheckClass::isBaseClassMutableMemberFunc(const Token *tok, const Scope *sco
     return false;
 }
 
-void CheckClass::initializeVarList(const Function &func, std::list<const Function *> &callstack, const Scope *scope, std::vector<Usage> &usage) const
+void CheckClassImpl::initializeVarList(const Function &func, std::list<const Function *> &callstack, const Scope *scope, std::vector<Usage> &usage) const
 {
     if (!func.functionScope)
         return;
@@ -1154,7 +1154,7 @@ void CheckClass::initializeVarList(const Function &func, std::list<const Functio
     }
 }
 
-void CheckClass::noConstructorError(const Token *tok, const std::string &classname, bool isStruct)
+void CheckClassImpl::noConstructorError(const Token *tok, const std::string &classname, bool isStruct)
 {
     // For performance reasons the constructor might be intentionally missing. Therefore this is not a "warning"
     const std::string message {"The " + std::string(isStruct ? "struct" : "class") + " '$symbol' does not declare a constructor although it has private member variables which likely require initialization."};
@@ -1162,14 +1162,14 @@ void CheckClass::noConstructorError(const Token *tok, const std::string &classna
     reportError(tok, Severity::style, "noConstructor", "$symbol:" + classname + '\n' + message + '\n' + verbose, CWE398, Certainty::normal);
 }
 
-void CheckClass::noExplicitConstructorError(const Token *tok, const std::string &classname, bool isStruct)
+void CheckClassImpl::noExplicitConstructorError(const Token *tok, const std::string &classname, bool isStruct)
 {
     const std::string message(std::string(isStruct ? "Struct" : "Class") + " '$symbol' has a constructor with 1 argument that is not explicit.");
     const std::string verbose(message + " Such, so called \"Converting constructors\", should in general be explicit for type safety reasons as that prevents unintended implicit conversions.");
     reportError(tok, Severity::style, "noExplicitConstructor", "$symbol:" + classname + '\n' + message + '\n' + verbose, CWE398, Certainty::normal);
 }
 
-void CheckClass::uninitVarError(const Token *tok, bool isprivate, FunctionType functionType, const std::string &classname, const std::string &varname, bool derived, bool inconclusive, bool noCtor)
+void CheckClassImpl::uninitVarError(const Token *tok, bool isprivate, FunctionType functionType, const std::string &classname, const std::string &varname, bool derived, bool inconclusive, bool noCtor)
 {
     std::string message("Member variable '$symbol' ");
     if (noCtor)
@@ -1189,7 +1189,7 @@ void CheckClass::uninitVarError(const Token *tok, bool isprivate, FunctionType f
     reportError(tok, Severity::warning, id, "$symbol:" + classname + "::" + varname + '\n' + message + '\n' + verbose, CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckClass::uninitVarError(const Token *tok, const std::string &classname, const std::string &varname)
+void CheckClassImpl::uninitVarError(const Token *tok, const std::string &classname, const std::string &varname)
 {
     const std::string message("Member variable '$symbol' is not initialized."); // report missing in-class initializer
     const std::string verbose {message + " Member variables of native types, pointers, or references are left uninitialized when the class is instantiated. That may cause bugs or undefined behavior."};
@@ -1197,7 +1197,7 @@ void CheckClass::uninitVarError(const Token *tok, const std::string &classname,
     reportError(tok, Severity::warning, id, "$symbol:" + classname + "::" + varname + '\n' + message + '\n' + verbose, CWE398, Certainty::normal);
 }
 
-void CheckClass::missingMemberCopyError(const Token *tok, FunctionType functionType, const std::string& classname, const std::string& varname)
+void CheckClassImpl::missingMemberCopyError(const Token *tok, FunctionType functionType, const std::string& classname, const std::string& varname)
 {
     const std::string ctor(functionType == FunctionType::eCopyConstructor ? "copy" : "move");
     const std::string action(functionType == FunctionType::eCopyConstructor ? "copied?" : "moved?");
@@ -1207,7 +1207,7 @@ void CheckClass::missingMemberCopyError(const Token *tok, FunctionType functionT
     reportError(tok, Severity::warning, "missingMemberCopy", message, CWE398, Certainty::inconclusive);
 }
 
-void CheckClass::operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive)
+void CheckClassImpl::operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive)
 {
     reportError(tok, Severity::warning, "operatorEqVarError", "$symbol:" + classname + "::" + varname + "\nMember variable '$symbol' is not assigned a value in '" + classname + "::operator='.", CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
@@ -1216,7 +1216,7 @@ void CheckClass::operatorEqVarError(const Token *tok, const std::string &classna
 // ClassCheck: Use initialization list instead of assignment
 //---------------------------------------------------------------------------
 
-void CheckClass::initializationListUsage()
+void CheckClassImpl::initializationListUsage()
 {
     if (!mSettings->severity.isEnabled(Severity::performance))
         return;
@@ -1300,7 +1300,7 @@ void CheckClass::initializationListUsage()
     }
 }
 
-void CheckClass::suggestInitializationList(const Token* tok, const std::string& varname)
+void CheckClassImpl::suggestInitializationList(const Token* tok, const std::string& varname)
 {
     reportError(tok, Severity::performance, "useInitializationList", "$symbol:" + varname + "\nVariable '$symbol' is assigned in constructor body. Consider performing initialization in initialization list.\n"
                 "When an object of a class is created, the constructors of all member variables are called consecutively "
@@ -1362,7 +1362,7 @@ static bool checkFunctionUsage(const Function *privfunc, const Scope* scope)
     return false; // Unused in this scope
 }
 
-void CheckClass::privateFunctions()
+void CheckClassImpl::privateFunctions()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedPrivateFunction"))
         return;
@@ -1422,7 +1422,7 @@ void CheckClass::privateFunctions()
     }
 }
 
-void CheckClass::unusedPrivateFunctionError(const Token* tok1, const Token *tok2, const std::string &classname, const std::string &funcname)
+void CheckClassImpl::unusedPrivateFunctionError(const Token* tok1, const Token *tok2, const std::string &classname, const std::string &funcname)
 {
     std::list<const Token *> toks{ tok1 };
     if (tok2)
@@ -1444,7 +1444,7 @@ static const Scope* findFunctionOf(const Scope* scope)
     return nullptr;
 }
 
-void CheckClass::checkMemset()
+void CheckClassImpl::checkMemset()
 {
     logChecker("CheckClass::checkMemset");
     const bool printWarnings = mSettings->severity.isEnabled(Severity::warning);
@@ -1540,7 +1540,7 @@ void CheckClass::checkMemset()
     }
 }
 
-void CheckClass::checkMemsetType(const Scope *start, const Token *tok, const Scope *type, bool allocation, std::set<const Scope *> parsedTypes)
+void CheckClassImpl::checkMemsetType(const Scope *start, const Token *tok, const Scope *type, bool allocation, std::set<const Scope *> parsedTypes)
 {
     // If type has been checked there is no need to check it again
     if (parsedTypes.find(type) != parsedTypes.end())
@@ -1606,7 +1606,7 @@ void CheckClass::checkMemsetType(const Scope *start, const Token *tok, const Sco
     }
 }
 
-void CheckClass::mallocOnClassWarning(const Token* tok, const std::string &memfunc, const Token* classTok)
+void CheckClassImpl::mallocOnClassWarning(const Token* tok, const std::string &memfunc, const Token* classTok)
 {
     std::list<const Token *> toks = { tok, classTok };
     reportError(toks, Severity::warning, "mallocOnClassWarning",
@@ -1616,7 +1616,7 @@ void CheckClass::mallocOnClassWarning(const Token* tok, const std::string &memfu
                 "since no constructor is called and class members remain uninitialized. Consider using 'new' instead.", CWE762, Certainty::normal);
 }
 
-void CheckClass::mallocOnClassError(const Token* tok, const std::string &memfunc, const Token* classTok, const std::string &classname)
+void CheckClassImpl::mallocOnClassError(const Token* tok, const std::string &memfunc, const Token* classTok, const std::string &classname)
 {
     std::list<const Token *> toks = { tok, classTok };
     reportError(toks, Severity::error, "mallocOnClassError",
@@ -1627,7 +1627,7 @@ void CheckClass::mallocOnClassError(const Token* tok, const std::string &memfunc
                 "since no constructor is called and class members remain uninitialized. Consider using 'new' instead.", CWE665, Certainty::normal);
 }
 
-void CheckClass::memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type, bool isContainer)
+void CheckClassImpl::memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type, bool isContainer)
 {
     const std::string typeStr = isContainer ? std::string() : (type + " that contains a ");
     const std::string msg = "$symbol:" + memfunc + "\n"
@@ -1639,14 +1639,14 @@ void CheckClass::memsetError(const Token *tok, const std::string &memfunc, const
     reportError(tok, Severity::error, "memsetClass", msg, CWE762, Certainty::normal);
 }
 
-void CheckClass::memsetErrorReference(const Token *tok, const std::string &memfunc, const std::string &type)
+void CheckClassImpl::memsetErrorReference(const Token *tok, const std::string &memfunc, const std::string &type)
 {
     reportError(tok, Severity::error, "memsetClassReference",
                 "$symbol:" + memfunc +"\n"
                 "Using '" + memfunc + "' on " + type + " that contains a reference.", CWE665, Certainty::normal);
 }
 
-void CheckClass::memsetErrorFloat(const Token *tok, const std::string &type)
+void CheckClassImpl::memsetErrorFloat(const Token *tok, const std::string &type)
 {
     reportError(tok, Severity::portability, "memsetClassFloat", "Using memset() on " + type + " which contains a floating point number.\n"
                 "Using memset() on " + type + " which contains a floating point number."
@@ -1661,7 +1661,7 @@ void CheckClass::memsetErrorFloat(const Token *tok, const std::string &type)
 // operator= should return a reference to *this
 //---------------------------------------------------------------------------
 
-void CheckClass::operatorEqRetRefThis()
+void CheckClassImpl::operatorEqRetRefThis()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("operatorEqRetRefThis"))
         return;
@@ -1680,13 +1680,13 @@ void CheckClass::operatorEqRetRefThis()
     }
 }
 
-void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last)
+void CheckClassImpl::checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last)
 {
     std::set<const Function*> analyzedFunctions;
     checkReturnPtrThis(scope, func, tok, last, analyzedFunctions);
 }
 
-void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last, std::set<const Function*>& analyzedFunctions)
+void CheckClassImpl::checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last, std::set<const Function*>& analyzedFunctions)
 {
     bool foundReturn = false;
 
@@ -1772,17 +1772,17 @@ void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, co
     operatorEqMissingReturnStatementError(func->token, func->access == AccessControl::Public);
 }
 
-void CheckClass::operatorEqRetRefThisError(const Token *tok)
+void CheckClassImpl::operatorEqRetRefThisError(const Token *tok)
 {
     reportError(tok, Severity::style, "operatorEqRetRefThis", "'operator=' should return reference to 'this' instance.", CWE398, Certainty::normal);
 }
 
-void CheckClass::operatorEqShouldBeLeftUnimplementedError(const Token *tok)
+void CheckClassImpl::operatorEqShouldBeLeftUnimplementedError(const Token *tok)
 {
     reportError(tok, Severity::style, "operatorEqShouldBeLeftUnimplemented", "'operator=' should either return reference to 'this' instance or be declared private and left unimplemented.", CWE398, Certainty::normal);
 }
 
-void CheckClass::operatorEqMissingReturnStatementError(const Token *tok, bool error)
+void CheckClassImpl::operatorEqMissingReturnStatementError(const Token *tok, bool error)
 {
     if (error) {
         reportError(tok, Severity::error, "operatorEqMissingReturnStatement", "No 'return' statement in non-void function causes undefined behavior.", CWE398, Certainty::normal);
@@ -1805,7 +1805,7 @@ void CheckClass::operatorEqMissingReturnStatementError(const Token *tok, bool er
 // assignment to self.
 //---------------------------------------------------------------------------
 
-void CheckClass::operatorEqToSelf()
+void CheckClassImpl::operatorEqToSelf()
 {
     if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("operatorEqToSelf"))
         return;
@@ -1846,7 +1846,7 @@ void CheckClass::operatorEqToSelf()
     }
 }
 
-bool CheckClass::hasAllocationInIfScope(const Function *func, const Scope* scope, const Token *ifStatementScopeStart) const
+bool CheckClassImpl::hasAllocationInIfScope(const Function *func, const Scope* scope, const Token *ifStatementScopeStart) const
 {
     const Token *end;
     if (ifStatementScopeStart->str() == "{")
@@ -1856,12 +1856,12 @@ bool CheckClass::hasAllocationInIfScope(const Function *func, const Scope* scope
     return hasAllocation(func, scope, ifStatementScopeStart, end);
 }
 
-bool CheckClass::hasAllocation(const Function *func, const Scope* scope) const
+bool CheckClassImpl::hasAllocation(const Function *func, const Scope* scope) const
 {
     return hasAllocation(func, scope, func->functionScope->bodyStart, func->functionScope->bodyEnd);
 }
 
-bool CheckClass::hasAllocation(const Function *func, const Scope* scope, const Token *start, const Token *end) const
+bool CheckClassImpl::hasAllocation(const Function *func, const Scope* scope, const Token *start, const Token *end) const
 {
     if (!end)
         end = func->functionScope->bodyEnd;
@@ -1907,7 +1907,7 @@ static bool isFalseKeyword(const Token* tok)
  * Checks if self-assignment test is inverse
  * For example 'if (this == &rhs)'
  */
-CheckClass::Bool CheckClass::isInverted(const Token *tok, const Token *rhs)
+CheckClassImpl::Bool CheckClassImpl::isInverted(const Token *tok, const Token *rhs)
 {
     bool res = true;
     for (const Token *itr = tok; itr && itr->str()!="("; itr=itr->astParent()) {
@@ -1936,7 +1936,7 @@ CheckClass::Bool CheckClass::isInverted(const Token *tok, const Token *rhs)
     return Bool::False;
 }
 
-const Token * CheckClass::getIfStmtBodyStart(const Token *tok, const Token *rhs)
+const Token * CheckClassImpl::getIfStmtBodyStart(const Token *tok, const Token *rhs)
 {
     const Token *top = tok->astTop();
     if (Token::simpleMatch(top->link(), ") {")) {
@@ -1952,7 +1952,7 @@ const Token * CheckClass::getIfStmtBodyStart(const Token *tok, const Token *rhs)
     return nullptr;
 }
 
-bool CheckClass::hasAssignSelf(const Function *func, const Token *rhs, const Token *&out_ifStatementScopeStart)
+bool CheckClassImpl::hasAssignSelf(const Function *func, const Token *rhs, const Token *&out_ifStatementScopeStart)
 {
     if (!rhs)
         return false;
@@ -1986,7 +1986,7 @@ bool CheckClass::hasAssignSelf(const Function *func, const Token *rhs, const Tok
     return false;
 }
 
-void CheckClass::operatorEqToSelfError(const Token *tok)
+void CheckClassImpl::operatorEqToSelfError(const Token *tok)
 {
     reportError(tok, Severity::warning, "operatorEqToSelf",
                 "'operator=' should check for assignment to self to avoid problems with dynamic memory.\n"
@@ -1998,7 +1998,7 @@ void CheckClass::operatorEqToSelfError(const Token *tok)
 // A destructor in a base class should be virtual
 //---------------------------------------------------------------------------
 
-void CheckClass::virtualDestructor()
+void CheckClassImpl::virtualDestructor()
 {
     // This error should only be given if:
     // * base class doesn't have virtual destructor
@@ -2133,7 +2133,7 @@ void CheckClass::virtualDestructor()
         virtualDestructorError(func->tokenDef, func->name(), "", true);
 }
 
-void CheckClass::virtualDestructorError(const Token *tok, const std::string &Base, const std::string &Derived, bool inconclusive)
+void CheckClassImpl::virtualDestructorError(const Token *tok, const std::string &Base, const std::string &Derived, bool inconclusive)
 {
     if (inconclusive) {
         if (mSettings->severity.isEnabled(Severity::warning))
@@ -2154,7 +2154,7 @@ void CheckClass::virtualDestructorError(const Token *tok, const std::string &Bas
 // warn for "this-x". The indented code may be "this->x"
 //---------------------------------------------------------------------------
 
-void CheckClass::thisSubtraction()
+void CheckClassImpl::thisSubtraction()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -2174,7 +2174,7 @@ void CheckClass::thisSubtraction()
     }
 }
 
-void CheckClass::thisSubtractionError(const Token *tok)
+void CheckClassImpl::thisSubtractionError(const Token *tok)
 {
     reportError(tok, Severity::warning, "thisSubtraction", "Suspicious pointer subtraction. Did you intend to write '->'?", CWE398, Certainty::normal);
 }
@@ -2183,7 +2183,7 @@ void CheckClass::thisSubtractionError(const Token *tok)
 // can member function be const?
 //---------------------------------------------------------------------------
 
-void CheckClass::checkConst()
+void CheckClassImpl::checkConst()
 {
     if (!mSettings->severity.isEnabled(Severity::style) &&
         !mSettings->isPremiumEnabled("functionConst") &&
@@ -2319,7 +2319,7 @@ static const Token* getFuncTokFromThis(const Token* tok) {
     return Token::Match(tok, "%name% (") ? tok : nullptr;
 }
 
-bool CheckClass::isMemberVar(const Scope *scope, const Token *tok) const
+bool CheckClassImpl::isMemberVar(const Scope *scope, const Token *tok) const
 {
     bool again = false;
 
@@ -2406,7 +2406,7 @@ bool CheckClass::isMemberVar(const Scope *scope, const Token *tok) const
     return false;
 }
 
-bool CheckClass::isMemberFunc(const Scope *scope, const Token *tok)
+bool CheckClassImpl::isMemberFunc(const Scope *scope, const Token *tok)
 {
     if (!tok->function()) {
         if (Token::simpleMatch(tok->astParent(), ".") && Token::simpleMatch(tok->astParent()->astOperand1(), "this"))
@@ -2449,7 +2449,7 @@ bool CheckClass::isMemberFunc(const Scope *scope, const Token *tok)
     return false;
 }
 
-bool CheckClass::isConstMemberFunc(const Scope *scope, const Token *tok)
+bool CheckClassImpl::isConstMemberFunc(const Scope *scope, const Token *tok)
 {
     if (!tok->function())
         return false;
@@ -2474,7 +2474,7 @@ bool CheckClass::isConstMemberFunc(const Scope *scope, const Token *tok)
     return false;
 }
 
-const std::set<std::string> CheckClass::stl_containers_not_const = { "map", "unordered_map", "std :: map|unordered_map <" }; // start pattern
+const std::set<std::string> CheckClassImpl::stl_containers_not_const = { "map", "unordered_map", "std :: map|unordered_map <" }; // start pattern
 
 static bool isNonConstPtrCast(const Token* tok)
 {
@@ -2484,7 +2484,7 @@ static bool isNonConstPtrCast(const Token* tok)
     return !vt || (vt->pointer > 0 && !vt->isConst(vt->pointer));
 }
 
-bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, MemberAccess& memberAccessed) const
+bool CheckClassImpl::checkConstFunc(const Scope *scope, const Function *func, MemberAccess& memberAccessed) const
 {
     if (mTokenizer->hasIfdef(func->functionScope->bodyStart, func->functionScope->bodyEnd))
         return false;
@@ -2758,12 +2758,12 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, Member
     return true;
 }
 
-void CheckClass::checkConstError(const Token *tok, const std::string &classname, const std::string &funcname, bool suggestStatic, bool foundAllBaseClasses)
+void CheckClassImpl::checkConstError(const Token *tok, const std::string &classname, const std::string &funcname, bool suggestStatic, bool foundAllBaseClasses)
 {
     checkConstError2(tok, nullptr, classname, funcname, suggestStatic, foundAllBaseClasses);
 }
 
-void CheckClass::checkConstError2(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &funcname, bool suggestStatic, bool foundAllBaseClasses)
+void CheckClassImpl::checkConstError2(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &funcname, bool suggestStatic, bool foundAllBaseClasses)
 {
     std::list<const Token *> toks{ tok1 };
     if (tok2)
@@ -2804,7 +2804,7 @@ namespace { // avoid one-definition-rule violation
     };
 }
 
-void CheckClass::initializerListOrder()
+void CheckClassImpl::initializerListOrder()
 {
     if (!mSettings->isPremiumEnabled("initializerList")) {
         if (!mSettings->severity.isEnabled(Severity::style))
@@ -2883,7 +2883,7 @@ void CheckClass::initializerListOrder()
     }
 }
 
-void CheckClass::initializerListError(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &varname, const std::string& argname)
+void CheckClassImpl::initializerListError(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &varname, const std::string& argname)
 {
     std::list<const Token *> toks = { tok1, tok2 };
     const std::string msg = argname.empty() ?
@@ -2904,7 +2904,7 @@ void CheckClass::initializerListError(const Token *tok1, const Token *tok2, cons
 // Check for self initialization in initialization list
 //---------------------------------------------------------------------------
 
-void CheckClass::checkSelfInitialization()
+void CheckClassImpl::checkSelfInitialization()
 {
     logChecker("CheckClass::checkSelfInitialization");
 
@@ -2933,7 +2933,7 @@ void CheckClass::checkSelfInitialization()
     }
 }
 
-void CheckClass::selfInitializationError(const Token* tok, const std::string& varname)
+void CheckClassImpl::selfInitializationError(const Token* tok, const std::string& varname)
 {
     reportError(tok, Severity::error, "selfInitialization", "$symbol:" + varname + "\nMember variable '$symbol' is initialized by itself.", CWE665, Certainty::normal);
 }
@@ -2943,7 +2943,7 @@ void CheckClass::selfInitializationError(const Token* tok, const std::string& va
 // Check for virtual function calls in constructor/destructor
 //---------------------------------------------------------------------------
 
-void CheckClass::checkVirtualFunctionCallInConstructor()
+void CheckClassImpl::checkVirtualFunctionCallInConstructor()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -2973,8 +2973,8 @@ void CheckClass::checkVirtualFunctionCallInConstructor()
     }
 }
 
-const std::list<const Token *> & CheckClass::getVirtualFunctionCalls(const Function & function,
-                                                                     std::map<const Function *, std::list<const Token *>> & virtualFunctionCallsMap)
+const std::list<const Token *> & CheckClassImpl::getVirtualFunctionCalls(const Function & function,
+                                                                         std::map<const Function *, std::list<const Token *>> & virtualFunctionCallsMap)
 {
     const auto found = utils::as_const(virtualFunctionCallsMap).find(&function);
     if (found != virtualFunctionCallsMap.end())
@@ -3031,7 +3031,7 @@ const std::list<const Token *> & CheckClass::getVirtualFunctionCalls(const Funct
     return virtualFunctionCalls;
 }
 
-void CheckClass::getFirstVirtualFunctionCallStack(
+void CheckClassImpl::getFirstVirtualFunctionCallStack(
     std::map<const Function *, std::list<const Token *>> & virtualFunctionCallsMap,
     const Token * callToken,
     std::list<const Token *> & pureFuncStack)
@@ -3051,7 +3051,7 @@ void CheckClass::getFirstVirtualFunctionCallStack(
     getFirstVirtualFunctionCallStack(virtualFunctionCallsMap, firstCall, pureFuncStack);
 }
 
-void CheckClass::virtualFunctionCallInConstructorError(
+void CheckClassImpl::virtualFunctionCallInConstructorError(
     const Function * scopeFunction,
     const std::list<const Token *> & tokStack,
     const std::string &funcname)
@@ -3089,7 +3089,7 @@ void CheckClass::virtualFunctionCallInConstructorError(
                 "Virtual function '" + funcname + "' is called from " + scopeFunctionTypeName + " '" + constructorName + "' at line " + std::to_string(lineNumber) + ". Dynamic binding is not used.", CWE(0U), Certainty::normal);
 }
 
-void CheckClass::pureVirtualFunctionCallInConstructorError(
+void CheckClassImpl::pureVirtualFunctionCallInConstructorError(
     const Function * scopeFunction,
     const std::list<const Token *> & tokStack,
     const std::string &purefuncname)
@@ -3114,7 +3114,7 @@ void CheckClass::pureVirtualFunctionCallInConstructorError(
 // Check for members hiding inherited members with the same name
 //---------------------------------------------------------------------------
 
-void CheckClass::checkDuplInheritedMembers()
+void CheckClassImpl::checkDuplInheritedMembers()
 {
     if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("duplInheritedMember"))
         return;
@@ -3203,7 +3203,7 @@ static std::vector<DuplMemberFuncInfo> getDuplInheritedMemberFunctionsRecursive(
     return results;
 }
 
-void CheckClass::checkDuplInheritedMembersRecursive(const Type* typeCurrent, const Type* typeBase)
+void CheckClassImpl::checkDuplInheritedMembersRecursive(const Type* typeCurrent, const Type* typeBase)
 {
     const auto resultsVar = getDuplInheritedMembersRecursive(typeCurrent, typeBase);
     for (const auto& r : resultsVar) {
@@ -3222,9 +3222,9 @@ void CheckClass::checkDuplInheritedMembersRecursive(const Type* typeCurrent, con
     }
 }
 
-void CheckClass::duplInheritedMembersError(const Token *tok1, const Token* tok2,
-                                           const std::string &derivedName, const std::string &baseName,
-                                           const std::string &memberName, bool derivedIsStruct, bool baseIsStruct, bool isFunction)
+void CheckClassImpl::duplInheritedMembersError(const Token *tok1, const Token* tok2,
+                                               const std::string &derivedName, const std::string &baseName,
+                                               const std::string &memberName, bool derivedIsStruct, bool baseIsStruct, bool isFunction)
 {
     ErrorPath errorPath;
     const std::string member = isFunction ? "function" : "variable";
@@ -3250,7 +3250,7 @@ enum class CtorType : std::uint8_t {
     WITH_BODY
 };
 
-void CheckClass::checkCopyCtorAndEqOperator()
+void CheckClassImpl::checkCopyCtorAndEqOperator()
 {
     // TODO: This is disabled because of #8388
     // The message must be clarified. How is the behaviour different?
@@ -3302,7 +3302,7 @@ void CheckClass::checkCopyCtorAndEqOperator()
     }
 }
 
-void CheckClass::copyCtorAndEqOperatorError(const Token *tok, const std::string &classname, bool isStruct, bool hasCopyCtor)
+void CheckClassImpl::copyCtorAndEqOperatorError(const Token *tok, const std::string &classname, bool isStruct, bool hasCopyCtor)
 {
     const std::string message = "$symbol:" + classname + "\n"
                                 "The " + std::string(isStruct ? "struct" : "class") + " '$symbol' has '" +
@@ -3312,7 +3312,7 @@ void CheckClass::copyCtorAndEqOperatorError(const Token *tok, const std::string
     reportError(tok, Severity::warning, "copyCtorAndEqOperator", message);
 }
 
-void CheckClass::checkOverride()
+void CheckClassImpl::checkOverride()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("missingOverride"))
         return;
@@ -3336,7 +3336,7 @@ void CheckClass::checkOverride()
     }
 }
 
-void CheckClass::overrideError(const Function *funcInBase, const Function *funcInDerived)
+void CheckClassImpl::overrideError(const Function *funcInBase, const Function *funcInDerived)
 {
     const std::string functionName = funcInDerived ? ((funcInDerived->isDestructor() ? "~" : "") + funcInDerived->name()) : "";
     const std::string funcType = (funcInDerived && funcInDerived->isDestructor()) ? "destructor" : "function";
@@ -3354,7 +3354,7 @@ void CheckClass::overrideError(const Function *funcInBase, const Function *funcI
                 Certainty::normal);
 }
 
-void CheckClass::uselessOverrideError(const Function *funcInBase, const Function *funcInDerived, bool isSameCode)
+void CheckClassImpl::uselessOverrideError(const Function *funcInBase, const Function *funcInDerived, bool isSameCode)
 {
     const std::string functionName = funcInDerived ? ((funcInDerived->isDestructor() ? "~" : "") + funcInDerived->name()) : "";
     const std::string funcType = (funcInDerived && funcInDerived->isDestructor()) ? "destructor" : "function";
@@ -3418,7 +3418,7 @@ static bool compareTokenRanges(const Token* start1, const Token* end1, const Tok
     return isEqual;
 }
 
-void CheckClass::checkUselessOverride()
+void CheckClassImpl::checkUselessOverride()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("uselessOverride"))
         return;
@@ -3499,7 +3499,7 @@ static const Variable* getSingleReturnVar(const Scope* scope) {
     return tok->variable();
 }
 
-void CheckClass::checkReturnByReference()
+void CheckClassImpl::checkReturnByReference()
 {
     if (!mSettings->severity.isEnabled(Severity::performance) && !mSettings->isPremiumEnabled("returnByReference"))
         return;
@@ -3542,14 +3542,14 @@ void CheckClass::checkReturnByReference()
     }
 }
 
-void CheckClass::returnByReferenceError(const Function* func, const Variable* var)
+void CheckClassImpl::returnByReferenceError(const Function* func, const Variable* var)
 {
     const Token* tok = func ? func->tokenDef : nullptr;
     const std::string message = "Function '" + (func ? func->name() : "func") + "()' should return member '" + (var ? var->name() : "var") + "' by const reference.";
     reportError(tok, Severity::performance, "returnByReference", message);
 }
 
-void CheckClass::checkThisUseAfterFree()
+void CheckClassImpl::checkThisUseAfterFree()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -3598,7 +3598,7 @@ void CheckClass::checkThisUseAfterFree()
     }
 }
 
-bool CheckClass::checkThisUseAfterFreeRecursive(const Scope *classScope, const Function *func, const Variable *selfPointer, std::set<const Function *> callstack, const Token *&freeToken)
+bool CheckClassImpl::checkThisUseAfterFreeRecursive(const Scope *classScope, const Function *func, const Variable *selfPointer, std::set<const Function *> callstack, const Token *&freeToken)
 {
     if (!func || !func->functionScope)
         return false;
@@ -3637,7 +3637,7 @@ bool CheckClass::checkThisUseAfterFreeRecursive(const Scope *classScope, const F
     return false;
 }
 
-void CheckClass::thisUseAfterFree(const Token *self, const Token *free, const Token *use)
+void CheckClassImpl::thisUseAfterFree(const Token *self, const Token *free, const Token *use)
 {
     std::string selfPointer = self ? self->str() : "ptr";
     ErrorPath errorPath = { ErrorPathItem(self, "Assuming '" + selfPointer + "' is used as 'this'"), ErrorPathItem(free, "Delete '" + selfPointer + "', invalidating 'this'"), ErrorPathItem(use, "Call method when 'this' is invalid") };
@@ -3649,7 +3649,7 @@ void CheckClass::thisUseAfterFree(const Token *self, const Token *free, const To
                 CWE(0), Certainty::normal);
 }
 
-void CheckClass::checkUnsafeClassRefMember()
+void CheckClassImpl::checkUnsafeClassRefMember()
 {
     if (!mSettings->safeChecks.classes || !mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -3673,7 +3673,7 @@ void CheckClass::checkUnsafeClassRefMember()
     }
 }
 
-void CheckClass::unsafeClassRefMemberError(const Token *tok, const std::string &varname)
+void CheckClassImpl::unsafeClassRefMemberError(const Token *tok, const std::string &varname)
 {
     reportError(tok, Severity::warning, "unsafeClassRefMember",
                 "$symbol:" + varname + "\n"
@@ -3833,9 +3833,8 @@ bool CheckClass::analyseWholeProgram(const CTU::FileInfo &ctu, const std::list<C
     (void)ctu;
     (void)settings;
 
-    CheckClass dummy(nullptr, &settings, &errorLogger);
-    dummy.
-    logChecker("CheckClass::analyseWholeProgram");
+    CheckClassImpl dummy(nullptr, &settings, &errorLogger);
+    dummy.logChecker("CheckClass::analyseWholeProgram");
 
     if (fileInfo.empty())
         return false;
@@ -3887,7 +3886,7 @@ void CheckClass::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
     if (tokenizer.isC())
         return;
 
-    CheckClass checkClass(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckClassImpl checkClass(&tokenizer, &tokenizer.getSettings(), errorLogger);
 
     // can't be a simplified check .. the 'sizeof' is used.
     checkClass.checkMemset();
@@ -3915,7 +3914,7 @@ void CheckClass::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 
 void CheckClass::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckClass c(nullptr, settings, errorLogger);
+    CheckClassImpl c(nullptr, settings, errorLogger);
     c.noConstructorError(nullptr, "classname", false);
     c.noExplicitConstructorError(nullptr, "classname", false);
     //c.copyConstructorMallocError(nullptr, 0, "var");
diff --git a/lib/checkclass.h b/lib/checkclass.h
index 2fb1862dad1..f23876a5c81 100644
--- a/lib/checkclass.h
+++ b/lib/checkclass.h
@@ -22,6 +22,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <cstdint>
@@ -49,23 +50,63 @@ enum class FunctionType : std::uint8_t;
 /** @brief %Check classes. Uninitialized member variables, non-conforming operators, missing virtual destructor, etc */
 class CPPCHECKLIB CheckClass : public Check {
     friend class TestClass;
+
     friend class TestConstructors;
+
     friend class TestUnusedPrivateFunction;
 
 public:
     /** @brief This constructor is used when registering the CheckClass */
-    CheckClass() : Check(myName()) {}
-
-    /** @brief Set of the STL types whose operator[] is not const */
-    static const std::set<std::string> stl_containers_not_const;
-
-private:
-    /** @brief This constructor is used when running checks. */
-    CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger);
+    CheckClass() : Check("Class") {}
 
     /** @brief Run checks on the normal token list */
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
+    /** @brief Parse current TU and extract file info */
+    Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings& /*settings*/, const std::string& currentConfig) const override;
+
+    Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override;
+
+    /** @brief Analyse all file infos for all TU */
+    bool analyseWholeProgram(const CTU::FileInfo &ctu, const std::list<Check::FileInfo*> &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override;
+
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+
+    std::string classInfo() const override {
+        return "Check the code for each class.\n"
+               "- Missing constructors and copy constructors\n"
+               //"- Missing allocation of memory in copy constructor\n"
+               "- Constructors which should be explicit\n"
+               "- Are all variables initialized by the constructors?\n"
+               "- Are all variables assigned by 'operator='?\n"
+               "- Warn if memset, memcpy etc are used on a class\n"
+               "- Warn if memory for classes is allocated with malloc()\n"
+               "- If it's a base class, check that the destructor is virtual\n"
+               "- Are there unused private functions?\n"
+               "- 'operator=' should check for assignment to self\n"
+               "- Constness for member functions\n"
+               "- Order of initializations\n"
+               "- Suggest usage of initialization list\n"
+               "- Initialization of a member with itself\n"
+               "- Suspicious subtraction from 'this'\n"
+               "- Call of pure virtual function in constructor/destructor\n"
+               "- Duplicated inherited data members\n"
+               // disabled for now "- If 'copy constructor' defined, 'operator=' also should be defined and vice versa\n"
+               "- Check that arbitrary usage of public interface does not result in division by zero\n"
+               "- Delete \"self pointer\" and then access 'this'\n"
+               "- Check that the 'override' keyword is used when overriding virtual functions\n"
+               "- Check that the 'one definition rule' is not violated\n";
+    }
+};
+
+class CPPCHECKLIB CheckClassImpl : public CheckImpl {
+public:
+    /** This constructor is used when running checks. */
+    CheckClassImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger);
+
+    /** @brief Set of the STL types whose operator[] is not const */
+    static const std::set<std::string> stl_containers_not_const;
+
     /** @brief %Check that all class constructors are ok */
     void constructors();
 
@@ -137,14 +178,6 @@ class CPPCHECKLIB CheckClass : public Check {
     /** @brief Unsafe class check - const reference member */
     void checkUnsafeClassRefMember();
 
-    /** @brief Parse current TU and extract file info */
-    Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings& /*settings*/, const std::string& currentConfig) const override;
-
-    Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override;
-
-    /** @brief Analyse all file infos for all TU */
-    bool analyseWholeProgram(const CTU::FileInfo &ctu, const std::list<Check::FileInfo*> &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override;
-
     const SymbolDatabase* mSymbolDatabase{};
 
     // Reporting errors..
@@ -187,38 +220,6 @@ class CPPCHECKLIB CheckClass : public Check {
     void unsafeClassRefMemberError(const Token *tok, const std::string &varname);
     void checkDuplInheritedMembersRecursive(const Type* typeCurrent, const Type* typeBase);
 
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "Class";
-    }
-
-    std::string classInfo() const override {
-        return "Check the code for each class.\n"
-               "- Missing constructors and copy constructors\n"
-               //"- Missing allocation of memory in copy constructor\n"
-               "- Constructors which should be explicit\n"
-               "- Are all variables initialized by the constructors?\n"
-               "- Are all variables assigned by 'operator='?\n"
-               "- Warn if memset, memcpy etc are used on a class\n"
-               "- Warn if memory for classes is allocated with malloc()\n"
-               "- If it's a base class, check that the destructor is virtual\n"
-               "- Are there unused private functions?\n"
-               "- 'operator=' should check for assignment to self\n"
-               "- Constness for member functions\n"
-               "- Order of initializations\n"
-               "- Suggest usage of initialization list\n"
-               "- Initialization of a member with itself\n"
-               "- Suspicious subtraction from 'this'\n"
-               "- Call of pure virtual function in constructor/destructor\n"
-               "- Duplicated inherited data members\n"
-               // disabled for now "- If 'copy constructor' defined, 'operator=' also should be defined and vice versa\n"
-               "- Check that arbitrary usage of public interface does not result in division by zero\n"
-               "- Delete \"self pointer\" and then access 'this'\n"
-               "- Check that the 'override' keyword is used when overriding virtual functions\n"
-               "- Check that the 'one definition rule' is not violated\n";
-    }
-
     // operatorEqRetRefThis helper functions
     void checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last);
     void checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last, std::set<const Function*>& analyzedFunctions);
diff --git a/lib/checkcondition.cpp b/lib/checkcondition.cpp
index cec3293ad27..81be6df5ea2 100644
--- a/lib/checkcondition.cpp
+++ b/lib/checkcondition.cpp
@@ -52,7 +52,7 @@ static const CWE CWE571(571U);   // Expression is Always True
 
 //---------------------------------------------------------------------------
 
-bool CheckCondition::diag(const Token* tok, bool insert)
+bool CheckConditionImpl::diag(const Token* tok, bool insert)
 {
     if (!tok)
         return false;
@@ -73,14 +73,14 @@ bool CheckCondition::diag(const Token* tok, bool insert)
     return true;
 }
 
-bool CheckCondition::diag(const Token* tok1, const Token* tok2)
+bool CheckConditionImpl::diag(const Token* tok1, const Token* tok2)
 {
     const bool b1 = diag(tok1);
     const bool b2 = diag(tok2);
     return b1 && b2;
 }
 
-bool CheckCondition::isAliased(const std::set<int> &vars) const
+bool CheckConditionImpl::isAliased(const std::set<int> &vars) const
 {
     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
         if (Token::Match(tok, "= & %var% ;") && vars.find(tok->tokAt(2)->varId()) != vars.end())
@@ -89,7 +89,7 @@ bool CheckCondition::isAliased(const std::set<int> &vars) const
     return false;
 }
 
-void CheckCondition::assignIf()
+void CheckConditionImpl::assignIf()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("assignIfError"))
         return;
@@ -162,12 +162,12 @@ static bool isParameterChanged(const Token *partok)
 }
 
 /** parse scopes recursively */
-bool CheckCondition::assignIfParseScope(const Token * const assignTok,
-                                        const Token * const startTok,
-                                        const nonneg int varid,
-                                        const bool islocal,
-                                        const char bitop,
-                                        const MathLib::bigint num)
+bool CheckConditionImpl::assignIfParseScope(const Token * const assignTok,
+                                            const Token * const startTok,
+                                            const nonneg int varid,
+                                            const bool islocal,
+                                            const char bitop,
+                                            const MathLib::bigint num)
 {
     bool ret = false;
 
@@ -240,7 +240,7 @@ bool CheckCondition::assignIfParseScope(const Token * const assignTok,
     return false;
 }
 
-void CheckCondition::assignIfError(const Token *tok1, const Token *tok2, const std::string &condition, bool result)
+void CheckConditionImpl::assignIfError(const Token *tok1, const Token *tok2, const std::string &condition, bool result)
 {
     if (tok2 && diag(tok2->tokAt(2)))
         return;
@@ -252,7 +252,7 @@ void CheckCondition::assignIfError(const Token *tok1, const Token *tok2, const s
 }
 
 
-void CheckCondition::mismatchingBitAndError(const Token *tok1, const MathLib::bigint num1, const Token *tok2, const MathLib::bigint num2)
+void CheckConditionImpl::mismatchingBitAndError(const Token *tok1, const MathLib::bigint num1, const Token *tok2, const MathLib::bigint num2)
 {
     std::list<const Token *> locations = { tok1, tok2 };
 
@@ -308,7 +308,7 @@ static bool isOperandExpanded(const Token *tok)
     return false;
 }
 
-void CheckCondition::checkBadBitmaskCheck()
+void CheckConditionImpl::checkBadBitmaskCheck()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("badBitmaskCheck"))
         return;
@@ -348,7 +348,7 @@ void CheckCondition::checkBadBitmaskCheck()
     }
 }
 
-void CheckCondition::badBitmaskCheckError(const Token *tok, bool isNoOp)
+void CheckConditionImpl::badBitmaskCheckError(const Token *tok, bool isNoOp)
 {
     if (isNoOp)
         reportError(tok, Severity::style, "badBitmaskCheck", "Operator '|' with one operand equal to zero is redundant.", CWE571, Certainty::normal);
@@ -356,7 +356,7 @@ void CheckCondition::badBitmaskCheckError(const Token *tok, bool isNoOp)
         reportError(tok, Severity::warning, "badBitmaskCheck", "Result of operator '|' is always true if one operand is non-zero. Did you intend to use '&'?", CWE571, Certainty::normal);
 }
 
-void CheckCondition::comparison()
+void CheckConditionImpl::comparison()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("comparisonError"))
         return;
@@ -421,7 +421,7 @@ void CheckCondition::comparison()
     }
 }
 
-void CheckCondition::comparisonError(const Token *tok, const std::string &bitop, MathLib::bigint value1, const std::string &op, MathLib::bigint value2, bool result)
+void CheckConditionImpl::comparisonError(const Token *tok, const std::string &bitop, MathLib::bigint value1, const std::string &op, MathLib::bigint value2, bool result)
 {
     std::ostringstream expression;
     expression << std::hex << "(X " << bitop << " 0x" << value1 << ") " << op << " 0x" << value2;
@@ -435,7 +435,7 @@ void CheckCondition::comparisonError(const Token *tok, const std::string &bitop,
     reportError(tok, Severity::style, "comparisonError", errmsg, CWE398, Certainty::normal);
 }
 
-bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token * const cond2, bool pure) const
+bool CheckConditionImpl::isOverlappingCond(const Token * const cond1, const Token * const cond2, bool pure) const
 {
     if (!cond1 || !cond2)
         return false;
@@ -476,7 +476,7 @@ bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token *
     return false;
 }
 
-void CheckCondition::duplicateCondition()
+void CheckConditionImpl::duplicateCondition()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("duplicateCondition"))
         return;
@@ -515,7 +515,7 @@ void CheckCondition::duplicateCondition()
     }
 }
 
-void CheckCondition::duplicateConditionError(const Token *tok1, const Token *tok2, ErrorPath errorPath)
+void CheckConditionImpl::duplicateConditionError(const Token *tok1, const Token *tok2, ErrorPath errorPath)
 {
     if (diag(tok1, tok2))
         return;
@@ -527,7 +527,7 @@ void CheckCondition::duplicateConditionError(const Token *tok1, const Token *tok
     reportError(std::move(errorPath), Severity::style, "duplicateCondition", msg, CWE398, Certainty::normal);
 }
 
-void CheckCondition::multiCondition()
+void CheckConditionImpl::multiCondition()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("multiCondition"))
         return;
@@ -570,7 +570,7 @@ void CheckCondition::multiCondition()
     }
 }
 
-void CheckCondition::overlappingElseIfConditionError(const Token *tok, nonneg int line1)
+void CheckConditionImpl::overlappingElseIfConditionError(const Token *tok, nonneg int line1)
 {
     if (diag(tok))
         return;
@@ -581,7 +581,7 @@ void CheckCondition::overlappingElseIfConditionError(const Token *tok, nonneg in
     reportError(tok, Severity::style, "multiCondition", errmsg.str(), CWE398, Certainty::normal);
 }
 
-void CheckCondition::oppositeElseIfConditionError(const Token *ifCond, const Token *elseIfCond, ErrorPath errorPath)
+void CheckConditionImpl::oppositeElseIfConditionError(const Token *ifCond, const Token *elseIfCond, ErrorPath errorPath)
 {
     if (diag(ifCond, elseIfCond))
         return;
@@ -629,7 +629,7 @@ static bool isNestedInLambda(const Scope* inner, const Scope* outer)
     return false;
 }
 
-void CheckCondition::multiCondition2()
+void CheckConditionImpl::multiCondition2()
 {
     if (!mSettings->severity.isEnabled(Severity::warning) &&
         !mSettings->isPremiumEnabled("identicalConditionAfterEarlyExit") &&
@@ -861,7 +861,7 @@ static std::string innerSmtString(const Token * tok)
     return top->str();
 }
 
-void CheckCondition::oppositeInnerConditionError(const Token *tok1, const Token* tok2, ErrorPath errorPath)
+void CheckConditionImpl::oppositeInnerConditionError(const Token *tok1, const Token* tok2, ErrorPath errorPath)
 {
     if (diag(tok1, tok2))
         return;
@@ -876,7 +876,7 @@ void CheckCondition::oppositeInnerConditionError(const Token *tok1, const Token*
     reportError(std::move(errorPath), Severity::warning, "oppositeInnerCondition", msg, CWE398, Certainty::normal);
 }
 
-void CheckCondition::overlappingInnerConditionError(const Token *tok1,  const Token* tok2, ErrorPath errorPath)
+void CheckConditionImpl::overlappingInnerConditionError(const Token *tok1,  const Token* tok2, ErrorPath errorPath)
 {
     if (diag(tok1, tok2))
         return;
@@ -891,7 +891,7 @@ void CheckCondition::overlappingInnerConditionError(const Token *tok1,  const To
     reportError(std::move(errorPath), Severity::warning, "overlappingInnerCondition", msg, CWE398, Certainty::normal);
 }
 
-void CheckCondition::identicalInnerConditionError(const Token *tok1, const Token* tok2, ErrorPath errorPath)
+void CheckConditionImpl::identicalInnerConditionError(const Token *tok1, const Token* tok2, ErrorPath errorPath)
 {
     if (diag(tok1, tok2))
         return;
@@ -906,7 +906,7 @@ void CheckCondition::identicalInnerConditionError(const Token *tok1, const Token
     reportError(std::move(errorPath), Severity::warning, "identicalInnerCondition", msg, CWE398, Certainty::normal);
 }
 
-void CheckCondition::identicalConditionAfterEarlyExitError(const Token *cond1, const Token* cond2, ErrorPath errorPath)
+void CheckConditionImpl::identicalConditionAfterEarlyExitError(const Token *cond1, const Token* cond2, ErrorPath errorPath)
 {
     if (diag(cond1, cond2))
         return;
@@ -1156,7 +1156,7 @@ static bool isIfConstexpr(const Token* tok) {
     return Token::simpleMatch(top->astOperand1(), "if") && top->astOperand1()->isConstexpr();
 }
 
-void CheckCondition::checkIncorrectLogicOperator()
+void CheckConditionImpl::checkIncorrectLogicOperator()
 {
     const bool printStyle = mSettings->severity.isEnabled(Severity::style);
     const bool printWarning = mSettings->severity.isEnabled(Severity::warning);
@@ -1367,7 +1367,7 @@ void CheckCondition::checkIncorrectLogicOperator()
     }
 }
 
-void CheckCondition::incorrectLogicOperatorError(const Token *tok, const std::string &condition, bool always, bool inconclusive, ErrorPath errors)
+void CheckConditionImpl::incorrectLogicOperatorError(const Token *tok, const std::string &condition, bool always, bool inconclusive, ErrorPath errors)
 {
     if (diag(tok))
         return;
@@ -1384,7 +1384,7 @@ void CheckCondition::incorrectLogicOperatorError(const Token *tok, const std::st
                     "Are these conditions necessary? Did you intend to use || instead? Are the numbers correct? Are you comparing the correct variables?", CWE570, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckCondition::redundantConditionError(const Token *tok, const std::string &text, bool inconclusive)
+void CheckConditionImpl::redundantConditionError(const Token *tok, const std::string &text, bool inconclusive)
 {
     if (diag(tok))
         return;
@@ -1394,7 +1394,7 @@ void CheckCondition::redundantConditionError(const Token *tok, const std::string
 //-----------------------------------------------------------------------------
 // Detect "(var % val1) > val2" where val2 is >= val1.
 //-----------------------------------------------------------------------------
-void CheckCondition::checkModuloAlwaysTrueFalse()
+void CheckConditionImpl::checkModuloAlwaysTrueFalse()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -1424,7 +1424,7 @@ void CheckCondition::checkModuloAlwaysTrueFalse()
     }
 }
 
-void CheckCondition::moduloAlwaysTrueFalseError(const Token* tok, const std::string& maxVal)
+void CheckConditionImpl::moduloAlwaysTrueFalseError(const Token* tok, const std::string& maxVal)
 {
     if (diag(tok))
         return;
@@ -1450,7 +1450,7 @@ static int countPar(const Token *tok1, const Token *tok2)
 // Clarify condition '(x = a < 0)' into '((x = a) < 0)' or '(x = (a < 0))'
 // Clarify condition '(a & b == c)' into '((a & b) == c)' or '(a & (b == c))'
 //---------------------------------------------------------------------------
-void CheckCondition::clarifyCondition()
+void CheckConditionImpl::clarifyCondition()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("clarifyCondition"))
         return;
@@ -1491,7 +1491,7 @@ void CheckCondition::clarifyCondition()
     }
 }
 
-void CheckCondition::clarifyConditionError(const Token *tok, bool assign, bool boolop)
+void CheckConditionImpl::clarifyConditionError(const Token *tok, bool assign, bool boolop)
 {
     std::string errmsg;
 
@@ -1514,7 +1514,7 @@ void CheckCondition::clarifyConditionError(const Token *tok, bool assign, bool b
                 errmsg, CWE398, Certainty::normal);
 }
 
-void CheckCondition::alwaysTrueFalse()
+void CheckConditionImpl::alwaysTrueFalse()
 {
     const bool pedantic = mSettings->isPremiumEnabled("alwaysTrue") ||
                           mSettings->isPremiumEnabled("alwaysFalse") ||
@@ -1669,7 +1669,7 @@ static std::string getConditionString(const Token* condition)
     return "Condition";
 }
 
-void CheckCondition::alwaysTrueFalseError(const Token* tok, const Token* condition, const ValueFlow::Value* value)
+void CheckConditionImpl::alwaysTrueFalseError(const Token* tok, const Token* condition, const ValueFlow::Value* value)
 {
     const bool alwaysTrue = value && (value->intvalue != 0 || value->isImpossible());
     const std::string expr = tok ? tok->expressionString() : std::string("x");
@@ -1683,7 +1683,7 @@ void CheckCondition::alwaysTrueFalseError(const Token* tok, const Token* conditi
                 (alwaysTrue ? CWE571 : CWE570), Certainty::normal);
 }
 
-void CheckCondition::checkInvalidTestForOverflow()
+void CheckConditionImpl::checkInvalidTestForOverflow()
 {
     // Interesting blogs:
     // https://www.airs.com/blog/archives/120
@@ -1771,7 +1771,7 @@ void CheckCondition::checkInvalidTestForOverflow()
     }
 }
 
-void CheckCondition::invalidTestForOverflow(const Token* tok, const ValueType *valueType, const std::string &replace)
+void CheckConditionImpl::invalidTestForOverflow(const Token* tok, const ValueType *valueType, const std::string &replace)
 {
     const std::string expr = (tok ? tok->expressionString() : std::string("x + c < x"));
     const std::string overflow = (valueType && valueType->pointer) ? "pointer overflow" : "signed integer overflow";
@@ -1786,7 +1786,7 @@ void CheckCondition::invalidTestForOverflow(const Token* tok, const ValueType *v
 }
 
 
-void CheckCondition::checkPointerAdditionResultNotNull()
+void CheckConditionImpl::checkPointerAdditionResultNotNull()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -1827,13 +1827,13 @@ void CheckCondition::checkPointerAdditionResultNotNull()
     }
 }
 
-void CheckCondition::pointerAdditionResultNotNullError(const Token *tok, const Token *calc)
+void CheckConditionImpl::pointerAdditionResultNotNullError(const Token *tok, const Token *calc)
 {
     const std::string s = calc ? calc->expressionString() : "ptr+1";
     reportError(tok, Severity::warning, "pointerAdditionResultNotNull", "Comparison is wrong. Result of '" + s + "' can't be 0 unless there is pointer overflow, and pointer overflow is undefined behaviour.");
 }
 
-void CheckCondition::checkDuplicateConditionalAssign()
+void CheckConditionImpl::checkDuplicateConditionalAssign()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("duplicateConditionalAssign"))
         return;
@@ -1890,7 +1890,7 @@ void CheckCondition::checkDuplicateConditionalAssign()
     }
 }
 
-void CheckCondition::duplicateConditionalAssignError(const Token *condTok, const Token* assignTok, bool isRedundant)
+void CheckConditionImpl::duplicateConditionalAssignError(const Token *condTok, const Token* assignTok, bool isRedundant)
 {
     ErrorPath errors;
     std::string msg = "Duplicate expression for the condition and assignment.";
@@ -1912,7 +1912,7 @@ void CheckCondition::duplicateConditionalAssignError(const Token *condTok, const
 }
 
 
-void CheckCondition::checkAssignmentInCondition()
+void CheckConditionImpl::checkAssignmentInCondition()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("assignmentInCondition"))
         return;
@@ -1946,7 +1946,7 @@ void CheckCondition::checkAssignmentInCondition()
     }
 }
 
-void CheckCondition::assignmentInCondition(const Token *eq)
+void CheckConditionImpl::assignmentInCondition(const Token *eq)
 {
     std::string expr = eq ? eq->expressionString() : "x=y";
 
@@ -1959,7 +1959,7 @@ void CheckCondition::assignmentInCondition(const Token *eq)
         Certainty::normal);
 }
 
-void CheckCondition::checkCompareValueOutOfTypeRange()
+void CheckConditionImpl::checkCompareValueOutOfTypeRange()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("compareValueOutOfTypeRangeError"))
         return;
@@ -2080,7 +2080,7 @@ void CheckCondition::checkCompareValueOutOfTypeRange()
     }
 }
 
-void CheckCondition::compareValueOutOfTypeRangeError(const Token *comparisonTok, const std::string &type, MathLib::bigint value, bool result)
+void CheckConditionImpl::compareValueOutOfTypeRangeError(const Token *comparisonTok, const std::string &type, MathLib::bigint value, bool result)
 {
     reportError(
         comparisonTok,
@@ -2093,7 +2093,7 @@ void CheckCondition::compareValueOutOfTypeRangeError(const Token *comparisonTok,
 
 void CheckCondition::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    CheckCondition checkCondition(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckConditionImpl checkCondition(&tokenizer, &tokenizer.getSettings(), errorLogger);
     checkCondition.multiCondition();
     checkCondition.clarifyCondition();   // not simplified because ifAssign
     checkCondition.multiCondition2();
@@ -2113,7 +2113,7 @@ void CheckCondition::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLog
 
 void CheckCondition::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckCondition c(nullptr, settings, errorLogger);
+    CheckConditionImpl c(nullptr, settings, errorLogger);
 
     c.assignIfError(nullptr, nullptr, "", false);
     c.badBitmaskCheckError(nullptr);
diff --git a/lib/checkcondition.h b/lib/checkcondition.h
index 2ea20158b11..be06dfbbfd2 100644
--- a/lib/checkcondition.h
+++ b/lib/checkcondition.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 #include "mathlib.h"
 #include "errortypes.h"
@@ -50,15 +51,39 @@ namespace ValueFlow {
 class CPPCHECKLIB CheckCondition : public Check {
 public:
     /** This constructor is used when registering the CheckAssignIf */
-    CheckCondition() : Check(myName()) {}
+    CheckCondition() : Check("Condition") {}
 
 private:
-    /** This constructor is used when running checks. */
-    CheckCondition(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+
+    std::string classInfo() const override {
+        return "Match conditions with assignments and other conditions:\n"
+               "- Mismatching assignment and comparison => comparison is always true/false\n"
+               "- Mismatching lhs and rhs in comparison => comparison is always true/false\n"
+               "- Detect usage of | where & should be used\n"
+               "- Duplicate condition and assignment\n"
+               "- Detect matching 'if' and 'else if' conditions\n"
+               "- Mismatching bitand (a &= 0xf0; a &= 1; => a = 0)\n"
+               "- Opposite inner condition is always false\n"
+               "- Identical condition after early exit is always false\n"
+               "- Condition that is always true/false\n"
+               "- Mutual exclusion over || always evaluating to true\n"
+               "- Comparisons of modulo results that are always true/false.\n"
+               "- Known variable values => condition is always true/false\n"
+               "- Invalid test for overflow. Some mainstream compilers remove such overflow tests when optimising code.\n"
+               "- Suspicious assignment of container/iterator in condition => condition is always true.\n";
+    }
+};
+
+
+class CPPCHECKLIB CheckConditionImpl : public CheckImpl {
+public:
+    /** This constructor is used when running checks. */
+    CheckConditionImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     /** mismatching assignment / comparison */
     void assignIf();
 
@@ -157,30 +182,6 @@ class CPPCHECKLIB CheckCondition : public Check {
 
     void checkCompareValueOutOfTypeRange();
     void compareValueOutOfTypeRangeError(const Token *comparisonTok, const std::string &type, MathLib::bigint value, bool result);
-
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "Condition";
-    }
-
-    std::string classInfo() const override {
-        return "Match conditions with assignments and other conditions:\n"
-               "- Mismatching assignment and comparison => comparison is always true/false\n"
-               "- Mismatching lhs and rhs in comparison => comparison is always true/false\n"
-               "- Detect usage of | where & should be used\n"
-               "- Duplicate condition and assignment\n"
-               "- Detect matching 'if' and 'else if' conditions\n"
-               "- Mismatching bitand (a &= 0xf0; a &= 1; => a = 0)\n"
-               "- Opposite inner condition is always false\n"
-               "- Identical condition after early exit is always false\n"
-               "- Condition that is always true/false\n"
-               "- Mutual exclusion over || always evaluating to true\n"
-               "- Comparisons of modulo results that are always true/false.\n"
-               "- Known variable values => condition is always true/false\n"
-               "- Invalid test for overflow. Some mainstream compilers remove such overflow tests when optimising code.\n"
-               "- Suspicious assignment of container/iterator in condition => condition is always true.\n";
-    }
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checkexceptionsafety.cpp b/lib/checkexceptionsafety.cpp
index 6da5281e80a..463e47bea1c 100644
--- a/lib/checkexceptionsafety.cpp
+++ b/lib/checkexceptionsafety.cpp
@@ -40,7 +40,7 @@ static const CWE CWE480(480U);   // Use of Incorrect Operator
 
 //---------------------------------------------------------------------------
 
-void CheckExceptionSafety::destructors()
+void CheckExceptionSafetyImpl::destructors()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -78,7 +78,7 @@ void CheckExceptionSafety::destructors()
     }
 }
 
-void CheckExceptionSafety::destructorsError(const Token * const tok, const std::string &className)
+void CheckExceptionSafetyImpl::destructorsError(const Token * const tok, const std::string &className)
 {
     reportError(tok, Severity::warning, "exceptThrowInDestructor",
                 "Class " + className + " is not safe, destructor throws exception\n"
@@ -88,7 +88,7 @@ void CheckExceptionSafety::destructorsError(const Token * const tok, const std::
 }
 
 
-void CheckExceptionSafety::deallocThrow()
+void CheckExceptionSafetyImpl::deallocThrow()
 {
     if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("exceptDeallocThrow"))
         return;
@@ -151,7 +151,7 @@ void CheckExceptionSafety::deallocThrow()
     }
 }
 
-void CheckExceptionSafety::deallocThrowError(const Token * const tok, const std::string &varname)
+void CheckExceptionSafetyImpl::deallocThrowError(const Token * const tok, const std::string &varname)
 {
     reportError(tok, Severity::warning, "exceptDeallocThrow", "Exception thrown in invalid state, '" +
                 varname + "' points at deallocated memory.", CWE398, Certainty::normal);
@@ -163,7 +163,7 @@ void CheckExceptionSafety::deallocThrowError(const Token * const tok, const std:
 //         throw err;            // <- should be just "throw;"
 //      }
 //---------------------------------------------------------------------------
-void CheckExceptionSafety::checkRethrowCopy()
+void CheckExceptionSafetyImpl::checkRethrowCopy()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("exceptRethrowCopy"))
         return;
@@ -196,7 +196,7 @@ void CheckExceptionSafety::checkRethrowCopy()
     }
 }
 
-void CheckExceptionSafety::rethrowCopyError(const Token * const tok, const std::string &varname)
+void CheckExceptionSafetyImpl::rethrowCopyError(const Token * const tok, const std::string &varname)
 {
     reportError(tok, Severity::style, "exceptRethrowCopy",
                 "Throwing a copy of the caught exception instead of rethrowing the original exception.\n"
@@ -207,7 +207,7 @@ void CheckExceptionSafety::rethrowCopyError(const Token * const tok, const std::
 //---------------------------------------------------------------------------
 //    try {} catch (std::exception err) {} <- Should be "std::exception& err"
 //---------------------------------------------------------------------------
-void CheckExceptionSafety::checkCatchExceptionByValue()
+void CheckExceptionSafetyImpl::checkCatchExceptionByValue()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("catchExceptionByValue"))
         return;
@@ -228,7 +228,7 @@ void CheckExceptionSafety::checkCatchExceptionByValue()
     }
 }
 
-void CheckExceptionSafety::catchExceptionByValueError(const Token *tok)
+void CheckExceptionSafetyImpl::catchExceptionByValueError(const Token *tok)
 {
     reportError(tok, Severity::style,
                 "catchExceptionByValue", "Exception should be caught by reference.\n"
@@ -281,7 +281,7 @@ static const Token * functionThrows(const Function * function)
 //    void func() throw() { throw x; }
 //    void func() __attribute__((nothrow)); void func() { throw x; }
 //--------------------------------------------------------------------------
-void CheckExceptionSafety::nothrowThrows()
+void CheckExceptionSafetyImpl::nothrowThrows()
 {
     logChecker("CheckExceptionSafety::nothrowThrows");
 
@@ -313,12 +313,12 @@ void CheckExceptionSafety::nothrowThrows()
     }
 }
 
-void CheckExceptionSafety::noexceptThrowError(const Token * const tok)
+void CheckExceptionSafetyImpl::noexceptThrowError(const Token * const tok)
 {
     reportError(tok, Severity::error, "throwInNoexceptFunction", "Unhandled exception thrown in function declared not to throw exceptions.", CWE398, Certainty::normal);
 }
 
-void CheckExceptionSafety::entryPointThrowError(const Token * const tok)
+void CheckExceptionSafetyImpl::entryPointThrowError(const Token * const tok)
 {
     reportError(tok, Severity::error, "throwInEntryPoint", "Unhandled exception thrown in function that is an entry point.", CWE398, Certainty::normal);
 }
@@ -326,7 +326,7 @@ void CheckExceptionSafety::entryPointThrowError(const Token * const tok)
 //--------------------------------------------------------------------------
 //    void func() { functionWithExceptionSpecification(); }
 //--------------------------------------------------------------------------
-void CheckExceptionSafety::unhandledExceptionSpecification()
+void CheckExceptionSafetyImpl::unhandledExceptionSpecification()
 {
     if ((!mSettings->severity.isEnabled(Severity::style) || !mSettings->certainty.isEnabled(Certainty::inconclusive)) &&
         !mSettings->isPremiumEnabled("unhandledExceptionSpecification"))
@@ -356,7 +356,7 @@ void CheckExceptionSafety::unhandledExceptionSpecification()
     }
 }
 
-void CheckExceptionSafety::unhandledExceptionSpecificationError(const Token * const tok1, const Token * const tok2, const std::string & funcname)
+void CheckExceptionSafetyImpl::unhandledExceptionSpecificationError(const Token * const tok1, const Token * const tok2, const std::string & funcname)
 {
     const std::string str1(tok1 ? tok1->str() : "foo");
     const std::list<const Token*> locationList = { tok1, tok2 };
@@ -369,7 +369,7 @@ void CheckExceptionSafety::unhandledExceptionSpecificationError(const Token * co
 //--------------------------------------------------------------------------
 // 7.6.18.4 If no exception is presently being handled, evaluating a throw-expression with no operand calls std​::​​terminate().
 //--------------------------------------------------------------------------
-void CheckExceptionSafety::rethrowNoCurrentException()
+void CheckExceptionSafetyImpl::rethrowNoCurrentException()
 {
     logChecker("CheckExceptionSafety::rethrowNoCurrentException");
     const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -400,7 +400,7 @@ void CheckExceptionSafety::rethrowNoCurrentException()
     }
 }
 
-void CheckExceptionSafety::rethrowNoCurrentExceptionError(const Token *tok)
+void CheckExceptionSafetyImpl::rethrowNoCurrentExceptionError(const Token *tok)
 {
     reportError(tok, Severity::error, "rethrowNoCurrentException",
                 "Rethrowing current exception with 'throw;', it seems there is no current exception to rethrow."
@@ -414,7 +414,7 @@ void CheckExceptionSafety::runChecks(const Tokenizer &tokenizer, ErrorLogger *er
     if (tokenizer.isC())
         return;
 
-    CheckExceptionSafety checkExceptionSafety(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckExceptionSafetyImpl checkExceptionSafety(&tokenizer, &tokenizer.getSettings(), errorLogger);
     checkExceptionSafety.destructors();
     checkExceptionSafety.deallocThrow();
     checkExceptionSafety.checkRethrowCopy();
@@ -426,7 +426,7 @@ void CheckExceptionSafety::runChecks(const Tokenizer &tokenizer, ErrorLogger *er
 
 void CheckExceptionSafety::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckExceptionSafety c(nullptr, settings, errorLogger);
+    CheckExceptionSafetyImpl c(nullptr, settings, errorLogger);
     c.destructorsError(nullptr, "Class");
     c.deallocThrowError(nullptr, "p");
     c.rethrowCopyError(nullptr, "varname");
diff --git a/lib/checkexceptionsafety.h b/lib/checkexceptionsafety.h
index 7c5a52b5605..bd44a649b1e 100644
--- a/lib/checkexceptionsafety.h
+++ b/lib/checkexceptionsafety.h
@@ -22,6 +22,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <string>
@@ -46,15 +47,33 @@ class Tokenizer;
 class CPPCHECKLIB CheckExceptionSafety : public Check {
 public:
     /** This constructor is used when registering the CheckClass */
-    CheckExceptionSafety() : Check(myName()) {}
+    CheckExceptionSafety() : Check("Exception Safety") {}
 
 private:
-    /** This constructor is used when running checks. */
-    CheckExceptionSafety(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
+    /** Generate all possible errors (for --errorlist) */
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+
+    /** wiki formatted description of the class (for --doc) */
+    std::string classInfo() const override {
+        return "Checking exception safety\n"
+               "- Throwing exceptions in destructors\n"
+               "- Throwing exception during invalid state\n"
+               "- Throwing a copy of a caught exception instead of rethrowing the original exception\n"
+               "- Exception caught by value instead of by reference\n"
+               "- Throwing exception in noexcept, nothrow(), __attribute__((nothrow)) or __declspec(nothrow) function\n"
+               "- Unhandled exception specification when calling function foo()\n"
+               "- Rethrow without currently handled exception\n";
+    }
+};
+
+class CPPCHECKLIB CheckExceptionSafetyImpl : public CheckImpl {
+public:
+    /** This constructor is used when running checks. */
+    CheckExceptionSafetyImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     /** Don't throw exceptions in destructors */
     void destructors();
 
@@ -87,26 +106,6 @@ class CPPCHECKLIB CheckExceptionSafety : public Check {
     void unhandledExceptionSpecificationError(const Token * tok1, const Token * tok2, const std::string & funcname);
     /** Rethrow without currently handled exception */
     void rethrowNoCurrentExceptionError(const Token *tok);
-
-    /** Generate all possible errors (for --errorlist) */
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
-    /** Short description of class (for --doc) */
-    static std::string myName() {
-        return "Exception Safety";
-    }
-
-    /** wiki formatted description of the class (for --doc) */
-    std::string classInfo() const override {
-        return "Checking exception safety\n"
-               "- Throwing exceptions in destructors\n"
-               "- Throwing exception during invalid state\n"
-               "- Throwing a copy of a caught exception instead of rethrowing the original exception\n"
-               "- Exception caught by value instead of by reference\n"
-               "- Throwing exception in noexcept, nothrow(), __attribute__((nothrow)) or __declspec(nothrow) function\n"
-               "- Unhandled exception specification when calling function foo()\n"
-               "- Rethrow without currently handled exception\n";
-    }
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checkfunctions.cpp b/lib/checkfunctions.cpp
index 733b868814e..47a3828de31 100644
--- a/lib/checkfunctions.cpp
+++ b/lib/checkfunctions.cpp
@@ -52,7 +52,7 @@ static const CWE CWE686(686U);  // Function Call With Incorrect Argument Type
 static const CWE CWE687(687U);  // Function Call With Incorrectly Specified Argument Value
 static const CWE CWE688(688U);  // Function Call With Incorrect Variable or Reference as Argument
 
-void CheckFunctions::checkProhibitedFunctions()
+void CheckFunctionsImpl::checkProhibitedFunctions()
 {
     const bool checkAlloca = mSettings->severity.isEnabled(Severity::warning) && ((mTokenizer->isC() && mSettings->standards.c >= Standards::C99) || mSettings->standards.cpp >= Standards::CPP11);
 
@@ -88,7 +88,8 @@ void CheckFunctions::checkProhibitedFunctions()
                 if (wi) {
                     if (mSettings->severity.isEnabled(wi->severity) && ((tok->isC() && mSettings->standards.c >= wi->standards.c) || (tok->isCpp() && mSettings->standards.cpp >= wi->standards.cpp))) {
                         const std::string daca = mSettings->daca ? "prohibited" : "";
-                        reportError(tok, wi->severity, daca + tok->str() + "Called", wi->message, CWE477, Certainty::normal);
+                        const std::string prefix = daca + tok->str();
+                        functionCalledError(tok, wi->severity, prefix, wi->message);
                     }
                 }
             }
@@ -96,10 +97,15 @@ void CheckFunctions::checkProhibitedFunctions()
     }
 }
 
+void CheckFunctionsImpl::functionCalledError(const Token* tok, Severity severity, const std::string& prefix, const std::string& msg)
+{
+    reportError(tok, severity, prefix + "Called", msg, CWE477, Certainty::normal);
+}
+
 //---------------------------------------------------------------------------
 // Check <valid>, <strz> and <not-bool>
 //---------------------------------------------------------------------------
-void CheckFunctions::invalidFunctionUsage()
+void CheckFunctionsImpl::invalidFunctionUsage()
 {
     logChecker("CheckFunctions::invalidFunctionUsage");
     const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -191,7 +197,7 @@ void CheckFunctions::invalidFunctionUsage()
     }
 }
 
-void CheckFunctions::invalidFunctionArgError(const Token *tok, const std::string &functionName, int argnr, const ValueFlow::Value *invalidValue, const std::string &validstr)
+void CheckFunctionsImpl::invalidFunctionArgError(const Token *tok, const std::string &functionName, int argnr, const ValueFlow::Value *invalidValue, const std::string &validstr)
 {
     std::ostringstream errmsg;
     errmsg << "$symbol:" << functionName << '\n';
@@ -220,7 +226,7 @@ void CheckFunctions::invalidFunctionArgError(const Token *tok, const std::string
                     Certainty::normal);
 }
 
-void CheckFunctions::invalidFunctionArgBoolError(const Token *tok, const std::string &functionName, int argnr)
+void CheckFunctionsImpl::invalidFunctionArgBoolError(const Token *tok, const std::string &functionName, int argnr)
 {
     std::ostringstream errmsg;
     errmsg << "$symbol:" << functionName << '\n';
@@ -228,7 +234,7 @@ void CheckFunctions::invalidFunctionArgBoolError(const Token *tok, const std::st
     reportError(tok, Severity::error, "invalidFunctionArgBool", errmsg.str(), CWE628, Certainty::normal);
 }
 
-void CheckFunctions::invalidFunctionArgStrError(const Token *tok, const std::string &functionName, nonneg int argnr)
+void CheckFunctionsImpl::invalidFunctionArgStrError(const Token *tok, const std::string &functionName, nonneg int argnr)
 {
     std::ostringstream errmsg;
     errmsg << "$symbol:" << functionName << '\n';
@@ -239,7 +245,7 @@ void CheckFunctions::invalidFunctionArgStrError(const Token *tok, const std::str
 //---------------------------------------------------------------------------
 // Check for ignored return values.
 //---------------------------------------------------------------------------
-void CheckFunctions::checkIgnoredReturnValue()
+void CheckFunctionsImpl::checkIgnoredReturnValue()
 {
     if (!mSettings->severity.isEnabled(Severity::warning) &&
         !mSettings->severity.isEnabled(Severity::style) &&
@@ -290,13 +296,13 @@ void CheckFunctions::checkIgnoredReturnValue()
     }
 }
 
-void CheckFunctions::ignoredReturnValueError(const Token* tok, const std::string& function)
+void CheckFunctionsImpl::ignoredReturnValueError(const Token* tok, const std::string& function)
 {
     reportError(tok, Severity::warning, "ignoredReturnValue",
                 "$symbol:" + function + "\nReturn value of function $symbol() is not used.", CWE252, Certainty::normal);
 }
 
-void CheckFunctions::ignoredReturnErrorCode(const Token* tok, const std::string& function)
+void CheckFunctionsImpl::ignoredReturnErrorCode(const Token* tok, const std::string& function)
 {
     reportError(tok, Severity::style, "ignoredReturnErrorCode",
                 "$symbol:" + function + "\nError code from the return value of function $symbol() is not used.", CWE252, Certainty::normal);
@@ -307,7 +313,7 @@ void CheckFunctions::ignoredReturnErrorCode(const Token* tok, const std::string&
 //---------------------------------------------------------------------------
 static const Token *checkMissingReturnScope(const Token *tok, const Library &library);
 
-void CheckFunctions::checkMissingReturn()
+void CheckFunctionsImpl::checkMissingReturn()
 {
     logChecker("CheckFunctions::checkMissingReturn");
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -425,7 +431,7 @@ static const Token *checkMissingReturnScope(const Token *tok, const Library &lib
     return nullptr;
 }
 
-void CheckFunctions::missingReturnError(const Token* tok)
+void CheckFunctionsImpl::missingReturnError(const Token* tok)
 {
     reportError(tok, Severity::error, "missingReturn",
                 "Found an exit path from function with non-void return type that has missing return statement", CWE758, Certainty::normal);
@@ -433,7 +439,7 @@ void CheckFunctions::missingReturnError(const Token* tok)
 //---------------------------------------------------------------------------
 // Detect passing wrong values to <cmath> functions like atan(0, x);
 //---------------------------------------------------------------------------
-void CheckFunctions::checkMathFunctions()
+void CheckFunctionsImpl::checkMathFunctions()
 {
     const bool styleC99 = mSettings->severity.isEnabled(Severity::style) && ((mTokenizer->isC() && mSettings->standards.c != Standards::C89) || (mTokenizer->isCPP() && mSettings->standards.cpp != Standards::CPP03));
     const bool printWarnings = mSettings->severity.isEnabled(Severity::warning);
@@ -494,7 +500,7 @@ void CheckFunctions::checkMathFunctions()
     }
 }
 
-void CheckFunctions::mathfunctionCallWarning(const Token *tok, const nonneg int numParam)
+void CheckFunctionsImpl::mathfunctionCallWarning(const Token *tok, const nonneg int numParam)
 {
     if (tok) {
         if (numParam == 1)
@@ -505,7 +511,7 @@ void CheckFunctions::mathfunctionCallWarning(const Token *tok, const nonneg int
         reportError(tok, Severity::warning, "wrongmathcall", "Passing value '#' to #() leads to implementation-defined result.", CWE758, Certainty::normal);
 }
 
-void CheckFunctions::mathfunctionCallWarning(const Token *tok, const std::string& oldexp, const std::string& newexp)
+void CheckFunctionsImpl::mathfunctionCallWarning(const Token *tok, const std::string& oldexp, const std::string& newexp)
 {
     reportError(tok, Severity::style, "unpreciseMathCall", "Expression '" + oldexp + "' can be replaced by '" + newexp + "' to avoid loss of precision.", CWE758, Certainty::normal);
 }
@@ -513,7 +519,7 @@ void CheckFunctions::mathfunctionCallWarning(const Token *tok, const std::string
 //---------------------------------------------------------------------------
 // memset(p, y, 0 /* bytes to fill */) <- 2nd and 3rd arguments inverted
 //---------------------------------------------------------------------------
-void CheckFunctions::memsetZeroBytes()
+void CheckFunctionsImpl::memsetZeroBytes()
 {
 // FIXME:
 //  Replace this with library configuration.
@@ -542,7 +548,7 @@ void CheckFunctions::memsetZeroBytes()
     }
 }
 
-void CheckFunctions::memsetZeroBytesError(const Token *tok)
+void CheckFunctionsImpl::memsetZeroBytesError(const Token *tok)
 {
     const std::string summary("memset() called to fill 0 bytes.");
     const std::string verbose(summary + " The second and third arguments might be inverted."
@@ -551,7 +557,7 @@ void CheckFunctions::memsetZeroBytesError(const Token *tok)
     reportError(tok, Severity::warning, "memsetZeroBytes", summary + "\n" + verbose, CWE687, Certainty::normal);
 }
 
-void CheckFunctions::memsetInvalid2ndParam()
+void CheckFunctionsImpl::memsetInvalid2ndParam()
 {
 // FIXME:
 //  Replace this with library configuration.
@@ -599,7 +605,7 @@ void CheckFunctions::memsetInvalid2ndParam()
     }
 }
 
-void CheckFunctions::memsetFloatError(const Token *tok, const std::string &var_value)
+void CheckFunctionsImpl::memsetFloatError(const Token *tok, const std::string &var_value)
 {
     const std::string message("The 2nd memset() argument '" + var_value +
                               "' is a float, its representation is implementation defined.");
@@ -608,7 +614,7 @@ void CheckFunctions::memsetFloatError(const Token *tok, const std::string &var_v
     reportError(tok, Severity::portability, "memsetFloat", message + "\n" + verbose, CWE688, Certainty::normal);
 }
 
-void CheckFunctions::memsetValueOutOfRangeError(const Token *tok, const std::string &value)
+void CheckFunctionsImpl::memsetValueOutOfRangeError(const Token *tok, const std::string &value)
 {
     const std::string message("The 2nd memset() argument '" + value + "' doesn't fit into an 'unsigned char'.");
     const std::string verbose(message + " The 2nd parameter is passed as an 'int', but the function fills the block of memory using the 'unsigned char' conversion of this value.");
@@ -619,7 +625,7 @@ void CheckFunctions::memsetValueOutOfRangeError(const Token *tok, const std::str
 // --check-library => warn for unconfigured functions
 //---------------------------------------------------------------------------
 
-void CheckFunctions::checkLibraryMatchFunctions()
+void CheckFunctionsImpl::checkLibraryMatchFunctions()
 {
     if (!mSettings->checkLibrary)
         return;
@@ -697,7 +703,7 @@ void CheckFunctions::checkLibraryMatchFunctions()
 // Check for problems to compiler apply (Named) Return Value Optimization for local variable
 // Technically we have different guarantees between standard versions
 // details: https://en.cppreference.com/w/cpp/language/copy_elision
-void CheckFunctions::returnLocalStdMove()
+void CheckFunctionsImpl::returnLocalStdMove()
 {
     if (!mTokenizer->isCPP() || mSettings->standards.cpp < Standards::CPP11)
         return;
@@ -727,7 +733,7 @@ void CheckFunctions::returnLocalStdMove()
     }
 }
 
-void CheckFunctions::copyElisionError(const Token *tok)
+void CheckFunctionsImpl::copyElisionError(const Token *tok)
 {
     reportError(tok,
                 Severity::performance,
@@ -736,7 +742,7 @@ void CheckFunctions::copyElisionError(const Token *tok)
                 " More: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-return-move-local");
 }
 
-void CheckFunctions::useStandardLibrary()
+void CheckFunctionsImpl::useStandardLibrary()
 {
     if (!mSettings->severity.isEnabled(Severity::style))
         return;
@@ -840,7 +846,7 @@ void CheckFunctions::useStandardLibrary()
     }
 }
 
-void CheckFunctions::useStandardLibraryError(const Token *tok, const std::string& expected)
+void CheckFunctionsImpl::useStandardLibraryError(const Token *tok, const std::string& expected)
 {
     reportError(tok, Severity::style,
                 "useStandardLibrary",
@@ -849,7 +855,7 @@ void CheckFunctions::useStandardLibraryError(const Token *tok, const std::string
 
 void CheckFunctions::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    CheckFunctions checkFunctions(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckFunctionsImpl checkFunctions(&tokenizer, &tokenizer.getSettings(), errorLogger);
 
     checkFunctions.checkIgnoredReturnValue();
     checkFunctions.checkMissingReturn();  // Missing "return" in exit path
@@ -868,10 +874,10 @@ void CheckFunctions::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLog
 
 void CheckFunctions::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckFunctions c(nullptr, settings, errorLogger);
+    CheckFunctionsImpl c(nullptr, settings, errorLogger);
 
     for (auto i = settings->library.functionwarn().cbegin(); i != settings->library.functionwarn().cend(); ++i) {
-        c.reportError(nullptr, Severity::style, i->first+"Called", i->second.message);
+        c.functionCalledError(nullptr, Severity::style, i->first, i->second.message);
     }
 
     c.invalidFunctionArgError(nullptr, "func_name", 1, nullptr,"1:4");
diff --git a/lib/checkfunctions.h b/lib/checkfunctions.h
index f5954d14043..7ea9e2833a2 100644
--- a/lib/checkfunctions.h
+++ b/lib/checkfunctions.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <string>
@@ -47,16 +48,34 @@ namespace ValueFlow {
 class CPPCHECKLIB CheckFunctions : public Check {
 public:
     /** This constructor is used when registering the CheckFunctions */
-    CheckFunctions() : Check(myName()) {}
+    CheckFunctions() : Check("Check function usage") {}
 
 private:
-    /** This constructor is used when running checks. */
-    CheckFunctions(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     /** @brief Run checks against the normal token list */
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+
+    std::string classInfo() const override {
+        return "Check function usage:\n"
+               "- missing 'return' in non-void function\n"
+               "- return value of certain functions not used\n"
+               "- invalid input values for functions\n"
+               "- Warn if a function is called whose usage is discouraged\n"
+               "- memset() third argument is zero\n"
+               "- memset() with a value out of range as the 2nd parameter\n"
+               "- memset() with a float as the 2nd parameter\n"
+               "- copy elision optimization for returning value affected by std::move\n"
+               "- use memcpy()/memset() instead of for loop\n";
+    }
+};
+
+class CPPCHECKLIB CheckFunctionsImpl : public CheckImpl {
+public:
+    /** This constructor is used when running checks. */
+    CheckFunctionsImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     /** Check for functions that should not be used */
     void checkProhibitedFunctions();
 
@@ -106,25 +125,7 @@ class CPPCHECKLIB CheckFunctions : public Check {
     void missingReturnError(const Token *tok);
     void copyElisionError(const Token *tok);
     void useStandardLibraryError(const Token *tok, const std::string& expected);
-
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "Check function usage";
-    }
-
-    std::string classInfo() const override {
-        return "Check function usage:\n"
-               "- missing 'return' in non-void function\n"
-               "- return value of certain functions not used\n"
-               "- invalid input values for functions\n"
-               "- Warn if a function is called whose usage is discouraged\n"
-               "- memset() third argument is zero\n"
-               "- memset() with a value out of range as the 2nd parameter\n"
-               "- memset() with a float as the 2nd parameter\n"
-               "- copy elision optimization for returning value affected by std::move\n"
-               "- use memcpy()/memset() instead of for loop\n";
-    }
+    void functionCalledError(const Token* tok, Severity severity, const std::string& prefix, const std::string& msg);
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/check.cpp b/lib/checkimpl.cpp
similarity index 60%
rename from lib/check.cpp
rename to lib/checkimpl.cpp
index 4033378e927..43e56cfa360 100644
--- a/lib/check.cpp
+++ b/lib/checkimpl.cpp
@@ -1,6 +1,6 @@
 /*
  * Cppcheck - A tool for static C/C++ code analysis
- * Copyright (C) 2007-2025 Cppcheck team.
+ * Copyright (C) 2007-2026 Cppcheck team.
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,9 +16,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-//---------------------------------------------------------------------------
-
-#include "check.h"
+#include "checkimpl.h"
 
 #include "errorlogger.h"
 #include "settings.h"
@@ -26,59 +24,35 @@
 #include "tokenize.h"
 #include "vfvalue.h"
 
-#include <cctype>
-#include <iostream>
+#include <cassert>
 #include <utility>
 
-//---------------------------------------------------------------------------
-
-Check::Check(std::string aname)
-    : mName(std::move(aname))
-{}
-
-void Check::writeToErrorList(const ErrorMessage &errmsg)
+void CheckImpl::reportError(const std::list<const Token *> &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe, Certainty certainty)
 {
-    std::cout << errmsg.toXML() << std::endl;
-}
-
+    assert(mErrorLogger);
 
-void Check::reportError(const std::list<const Token *> &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe, Certainty certainty)
-{
     // TODO: report debug warning when error is for a disabled severity
     const ErrorMessage errmsg(callstack, mTokenizer ? &mTokenizer->list : nullptr, severity, id, msg, cwe, certainty);
-    if (mErrorLogger)
-        mErrorLogger->reportErr(errmsg);
-    else
-        writeToErrorList(errmsg);
+    mErrorLogger->reportErr(errmsg);
 }
 
-void Check::reportError(ErrorPath errorPath, Severity severity, const char id[], const std::string &msg, const CWE &cwe, Certainty certainty)
+void CheckImpl::reportError(ErrorPath errorPath, Severity severity, const char id[], const std::string &msg, const CWE &cwe, Certainty certainty)
 {
+    assert(mErrorLogger);
+
     // TODO: report debug warning when error is for a disabled severity
     const ErrorMessage errmsg(std::move(errorPath), mTokenizer ? &mTokenizer->list : nullptr, severity, id, msg, cwe, certainty);
-    if (mErrorLogger)
-        mErrorLogger->reportErr(errmsg);
-    else
-        writeToErrorList(errmsg);
+    mErrorLogger->reportErr(errmsg);
 }
 
-bool Check::wrongData(const Token *tok, const char *str)
+bool CheckImpl::wrongData(const Token *tok, const char *str)
 {
     if (mSettings->daca)
         reportError(tok, Severity::debug, "DacaWrongData", "Wrong data detected by condition " + std::string(str));
     return true;
 }
 
-std::string Check::getMessageId(const ValueFlow::Value &value, const char id[])
-{
-    if (value.condition != nullptr)
-        return id + std::string("Cond");
-    if (value.safe)
-        return std::string("safe") + static_cast<char>(std::toupper(id[0])) + (id + 1);
-    return id;
-}
-
-ErrorPath Check::getErrorPath(const Token* errtok, const ValueFlow::Value* value, std::string bug) const
+ErrorPath CheckImpl::getErrorPath(const Token* errtok, const ValueFlow::Value* value, std::string bug) const
 {
     ErrorPath errorPath;
     if (!value) {
@@ -96,9 +70,8 @@ ErrorPath Check::getErrorPath(const Token* errtok, const ValueFlow::Value* value
     return errorPath;
 }
 
-void Check::logChecker(const char id[])
+void CheckImpl::logChecker(const char id[])
 {
     if (!mSettings->buildDir.empty() || mSettings->collectLogCheckers())
         reportError(nullptr, Severity::internal, "logChecker", id);
 }
-
diff --git a/lib/checkimpl.h b/lib/checkimpl.h
new file mode 100644
index 00000000000..35ad7de92e1
--- /dev/null
+++ b/lib/checkimpl.h
@@ -0,0 +1,85 @@
+/*
+ * Cppcheck - A tool for static C/C++ code analysis
+ * Copyright (C) 2007-2026 Cppcheck team.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef checkimplH
+#define checkimplH
+
+#include "config.h"
+#include "errortypes.h"
+
+#include <list>
+#include <string>
+
+class Settings;
+class ErrorLogger;
+class Tokenizer;
+class Check;
+class Token;
+namespace ValueFlow {
+    class Value;
+}
+
+class CPPCHECKLIB CheckImpl
+{
+public:
+    /** This constructor is used when running checks. */
+    CheckImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : mTokenizer(tokenizer), mSettings(settings), mErrorLogger(errorLogger) {}
+
+    CheckImpl(const CheckImpl &) = delete;
+    Check& operator=(const CheckImpl &) = delete;
+
+protected:
+    const Tokenizer* const mTokenizer{};
+    const Settings* const mSettings{};
+    ErrorLogger* const mErrorLogger{};
+
+    /** report an error */
+    void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg) {
+        reportError(tok, severity, id, msg, CWE(0U), Certainty::normal);
+    }
+
+    /** report an error */
+    void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg, const CWE &cwe, Certainty certainty) {
+        const std::list<const Token *> callstack(1, tok);
+        reportError(callstack, severity, id, msg, cwe, certainty);
+    }
+
+    /** report an error */
+    void reportError(const std::list<const Token *> &callstack, Severity severity, const std::string &id, const std::string &msg) {
+        reportError(callstack, severity, id, msg, CWE(0U), Certainty::normal);
+    }
+
+    /** report an error */
+    void reportError(const std::list<const Token *> &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe, Certainty certainty);
+
+    void reportError(ErrorPath errorPath, Severity severity, const char id[], const std::string &msg, const CWE &cwe, Certainty certainty);
+
+    ErrorPath getErrorPath(const Token* errtok, const ValueFlow::Value* value, std::string bug) const;
+
+    /**
+     * Use WRONG_DATA in checkers when you check for wrong data. That
+     * will call this method
+     */
+    bool wrongData(const Token *tok, const char *str);
+
+public: // TODO: should be protected
+    void logChecker(const char id[]);
+};
+
+#endif // checkimplH
diff --git a/lib/checkinternal.cpp b/lib/checkinternal.cpp
index ed39b4db96a..10af0543cec 100644
--- a/lib/checkinternal.cpp
+++ b/lib/checkinternal.cpp
@@ -31,7 +31,7 @@
 #include <set>
 #include <vector>
 
-void CheckInternal::checkTokenMatchPatterns()
+void CheckInternalImpl::checkTokenMatchPatterns()
 {
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope *scope : symbolDatabase->functionScopes) {
@@ -82,7 +82,7 @@ void CheckInternal::checkTokenMatchPatterns()
     }
 }
 
-void CheckInternal::checkRedundantTokCheck()
+void CheckInternalImpl::checkRedundantTokCheck()
 {
     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
         if (Token::Match(tok, "&& Token :: simpleMatch|Match|findsimplematch|findmatch (")) {
@@ -117,13 +117,13 @@ void CheckInternal::checkRedundantTokCheck()
 }
 
 
-void CheckInternal::checkRedundantTokCheckError(const Token* tok)
+void CheckInternalImpl::checkRedundantTokCheckError(const Token* tok)
 {
     reportError(tok, Severity::style, "redundantTokCheck",
                 "Unnecessary check of \"" + (tok? tok->expressionString(): "") + "\", match-function already checks if it is null.");
 }
 
-void CheckInternal::checkTokenSimpleMatchPatterns()
+void CheckInternalImpl::checkTokenSimpleMatchPatterns()
 {
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope* scope : symbolDatabase->functionScopes) {
@@ -207,7 +207,7 @@ namespace {
     };
 }
 
-void CheckInternal::checkMissingPercentCharacter()
+void CheckInternalImpl::checkMissingPercentCharacter()
 {
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope* scope : symbolDatabase->functionScopes) {
@@ -248,7 +248,7 @@ void CheckInternal::checkMissingPercentCharacter()
     }
 }
 
-void CheckInternal::checkUnknownPattern()
+void CheckInternalImpl::checkUnknownPattern()
 {
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope* scope : symbolDatabase->functionScopes) {
@@ -282,7 +282,7 @@ void CheckInternal::checkUnknownPattern()
     }
 }
 
-void CheckInternal::checkRedundantNextPrevious()
+void CheckInternalImpl::checkRedundantNextPrevious()
 {
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope* scope : symbolDatabase->functionScopes) {
@@ -305,7 +305,7 @@ void CheckInternal::checkRedundantNextPrevious()
     }
 }
 
-void CheckInternal::checkExtraWhitespace()
+void CheckInternalImpl::checkExtraWhitespace()
 {
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope* scope : symbolDatabase->functionScopes) {
@@ -331,46 +331,46 @@ void CheckInternal::checkExtraWhitespace()
     }
 }
 
-void CheckInternal::simplePatternError(const Token* tok, const std::string& pattern, const std::string &funcname)
+void CheckInternalImpl::simplePatternError(const Token* tok, const std::string& pattern, const std::string &funcname)
 {
     reportError(tok, Severity::warning, "simplePatternError",
                 "Found simple pattern inside Token::" + funcname + "() call: \"" + pattern + "\""
                 );
 }
 
-void CheckInternal::complexPatternError(const Token* tok, const std::string& pattern, const std::string &funcname)
+void CheckInternalImpl::complexPatternError(const Token* tok, const std::string& pattern, const std::string &funcname)
 {
     reportError(tok, Severity::error, "complexPatternError",
                 "Found complex pattern inside Token::" + funcname + "() call: \"" + pattern + "\""
                 );
 }
 
-void CheckInternal::missingPercentCharacterError(const Token* tok, const std::string& pattern, const std::string& funcname)
+void CheckInternalImpl::missingPercentCharacterError(const Token* tok, const std::string& pattern, const std::string& funcname)
 {
     reportError(tok, Severity::error, "missingPercentCharacter",
                 "Missing percent end character in Token::" + funcname + "() pattern: \"" + pattern + "\""
                 );
 }
 
-void CheckInternal::unknownPatternError(const Token* tok, const std::string& pattern)
+void CheckInternalImpl::unknownPatternError(const Token* tok, const std::string& pattern)
 {
     reportError(tok, Severity::error, "unknownPattern",
                 "Unknown pattern used: \"" + pattern + "\"");
 }
 
-void CheckInternal::redundantNextPreviousError(const Token* tok, const std::string& func1, const std::string& func2)
+void CheckInternalImpl::redundantNextPreviousError(const Token* tok, const std::string& func1, const std::string& func2)
 {
     reportError(tok, Severity::style, "redundantNextPrevious",
                 "Call to 'Token::" + func1 + "()' followed by 'Token::" + func2 + "()' can be simplified.");
 }
 
-void CheckInternal::orInComplexPattern(const Token* tok, const std::string& pattern, const std::string &funcname)
+void CheckInternalImpl::orInComplexPattern(const Token* tok, const std::string& pattern, const std::string &funcname)
 {
     reportError(tok, Severity::error, "orInComplexPattern",
                 "Token::" + funcname + "() pattern \"" + pattern + "\" contains \"||\" or \"|\". Replace it by \"%oror%\" or \"%or%\".");
 }
 
-void CheckInternal::extraWhitespaceError(const Token* tok, const std::string& pattern, const std::string &funcname)
+void CheckInternalImpl::extraWhitespaceError(const Token* tok, const std::string& pattern, const std::string &funcname)
 {
     reportError(tok, Severity::warning, "extraWhitespaceError",
                 "Found extra whitespace inside Token::" + funcname + "() call: \"" + pattern + "\""
@@ -382,7 +382,7 @@ void CheckInternal::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogg
     if (!tokenizer.getSettings().checks.isEnabled(Checks::internalCheck))
         return;
 
-    CheckInternal checkInternal(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckInternalImpl checkInternal(&tokenizer, &tokenizer.getSettings(), errorLogger);
 
     checkInternal.checkTokenMatchPatterns();
     checkInternal.checkTokenSimpleMatchPatterns();
@@ -395,7 +395,7 @@ void CheckInternal::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogg
 
 void CheckInternal::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckInternal c(nullptr, settings, errorLogger);
+    CheckInternalImpl c(nullptr, settings, errorLogger);
     c.simplePatternError(nullptr, "class {", "Match");
     c.complexPatternError(nullptr, "%type% ( )", "Match");
     c.missingPercentCharacterError(nullptr, "%num", "Match");
diff --git a/lib/checkinternal.h b/lib/checkinternal.h
index d62d9698b8d..2d95e3ed7e4 100644
--- a/lib/checkinternal.h
+++ b/lib/checkinternal.h
@@ -25,6 +25,7 @@
 #ifdef CHECK_INTERNAL
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <string>
@@ -42,15 +43,26 @@ class Settings;
 class CPPCHECKLIB CheckInternal : public Check {
 public:
     /** This constructor is used when registering the CheckClass */
-    CheckInternal() : Check(myName()) {}
+    CheckInternal() : Check("cppcheck internal API usage") {}
 
 private:
-    /** This constructor is used when running checks. */
-    CheckInternal(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+
+    std::string classInfo() const override {
+        // Don't include these checks on the WIKI where people can read what
+        // checks there are. These checks are not intended for users.
+        return "";
+    }
+};
+
+class CPPCHECKLIB CheckInternalImpl : public CheckImpl {
+public:
+    /** This constructor is used when running checks. */
+    CheckInternalImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     /** @brief %Check if a simple pattern is used inside Token::Match or Token::findmatch */
     void checkTokenMatchPatterns();
 
@@ -80,18 +92,6 @@ class CPPCHECKLIB CheckInternal : public Check {
     void orInComplexPattern(const Token *tok, const std::string &pattern, const std::string &funcname);
     void extraWhitespaceError(const Token *tok, const std::string &pattern, const std::string &funcname);
     void checkRedundantTokCheckError(const Token *tok);
-
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "cppcheck internal API usage";
-    }
-
-    std::string classInfo() const override {
-        // Don't include these checks on the WIKI where people can read what
-        // checks there are. These checks are not intended for users.
-        return "";
-    }
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checkio.cpp b/lib/checkio.cpp
index 4161b9b224d..f1cb4670c50 100644
--- a/lib/checkio.cpp
+++ b/lib/checkio.cpp
@@ -58,7 +58,7 @@ static const CWE CWE910(910U);  // Use of Expired File Descriptor
 //---------------------------------------------------------------------------
 //    std::cout << std::cout;
 //---------------------------------------------------------------------------
-void CheckIO::checkCoutCerrMisusage()
+void CheckIOImpl::checkCoutCerrMisusage()
 {
     if (mTokenizer->isC())
         return;
@@ -80,7 +80,7 @@ void CheckIO::checkCoutCerrMisusage()
     }
 }
 
-void CheckIO::coutCerrMisusageError(const Token* tok, const std::string& streamName)
+void CheckIOImpl::coutCerrMisusageError(const Token* tok, const std::string& streamName)
 {
     reportError(tok, Severity::error, "coutCerrMisusage", "Invalid usage of output stream: '<< std::" + streamName + "'.", CWE398, Certainty::normal);
 }
@@ -119,7 +119,7 @@ namespace {
     const std::unordered_set<std::string> whitelist = { "clearerr", "feof", "ferror", "fgetpos", "ftell", "setbuf", "setvbuf", "ungetc", "ungetwc" };
 }
 
-void CheckIO::checkFileUsage()
+void CheckIOImpl::checkFileUsage()
 {
     const bool windows = mSettings->platform.isWindows();
     const bool printPortability = mSettings->severity.isEnabled(Severity::portability);
@@ -379,37 +379,37 @@ void CheckIO::checkFileUsage()
     }
 }
 
-void CheckIO::fflushOnInputStreamError(const Token *tok, const std::string &varname)
+void CheckIOImpl::fflushOnInputStreamError(const Token *tok, const std::string &varname)
 {
     reportError(tok, Severity::portability,
                 "fflushOnInputStream", "fflush() called on input stream '" + varname + "' may result in undefined behaviour on non-linux systems.", CWE398, Certainty::normal);
 }
 
-void CheckIO::ioWithoutPositioningError(const Token *tok)
+void CheckIOImpl::ioWithoutPositioningError(const Token *tok)
 {
     reportError(tok, Severity::error,
                 "IOWithoutPositioning", "Read and write operations without a call to a positioning function (fseek, fsetpos or rewind) or fflush in between result in undefined behaviour.", CWE664, Certainty::normal);
 }
 
-void CheckIO::readWriteOnlyFileError(const Token *tok)
+void CheckIOImpl::readWriteOnlyFileError(const Token *tok)
 {
     reportError(tok, Severity::error,
                 "readWriteOnlyFile", "Read operation on a file that was opened only for writing.", CWE664, Certainty::normal);
 }
 
-void CheckIO::writeReadOnlyFileError(const Token *tok)
+void CheckIOImpl::writeReadOnlyFileError(const Token *tok)
 {
     reportError(tok, Severity::error,
                 "writeReadOnlyFile", "Write operation on a file that was opened only for reading.", CWE664, Certainty::normal);
 }
 
-void CheckIO::useClosedFileError(const Token *tok)
+void CheckIOImpl::useClosedFileError(const Token *tok)
 {
     reportError(tok, Severity::error,
                 "useClosedFile", "Used file that is not opened.", CWE910, Certainty::normal);
 }
 
-void CheckIO::fcloseInLoopConditionError(const Token *tok, const std::string &varname)
+void CheckIOImpl::fcloseInLoopConditionError(const Token *tok, const std::string &varname)
 {
     reportError(tok, Severity::warning,
                 "fcloseInLoopCondition",
@@ -418,13 +418,13 @@ void CheckIO::fcloseInLoopConditionError(const Token *tok, const std::string &va
                 CWE910, Certainty::normal);
 }
 
-void CheckIO::seekOnAppendedFileError(const Token *tok)
+void CheckIOImpl::seekOnAppendedFileError(const Token *tok)
 {
     reportError(tok, Severity::warning,
                 "seekOnAppendedFile", "Repositioning operation performed on a file opened in append mode has no effect.", CWE398, Certainty::normal);
 }
 
-void CheckIO::incompatibleFileOpenError(const Token *tok, const std::string &filename)
+void CheckIOImpl::incompatibleFileOpenError(const Token *tok, const std::string &filename)
 {
     reportError(tok, Severity::warning,
                 "incompatibleFileOpen", "The file '" + filename + "' is opened for read and write access at the same time on different streams", CWE664, Certainty::normal);
@@ -434,7 +434,7 @@ void CheckIO::incompatibleFileOpenError(const Token *tok, const std::string &fil
 //---------------------------------------------------------------------------
 // scanf without field width limits can crash with huge input data
 //---------------------------------------------------------------------------
-void CheckIO::invalidScanf()
+void CheckIOImpl::invalidScanf()
 {
     if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("invalidscanf"))
         return;
@@ -481,7 +481,7 @@ void CheckIO::invalidScanf()
     }
 }
 
-void CheckIO::invalidScanfError(const Token *tok)
+void CheckIOImpl::invalidScanfError(const Token *tok)
 {
     const std::string fname = (tok ? tok->str() : std::string("scanf"));
     reportError(tok, Severity::warning,
@@ -553,7 +553,7 @@ static inline bool typesMatch(const std::string& iToTest, const std::string& iTy
     return (iToTest == iTypename) || (iToTest == iOptionalPrefix + iTypename);
 }
 
-void CheckIO::checkWrongPrintfScanfArguments()
+void CheckIOImpl::checkWrongPrintfScanfArguments()
 {
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     const bool isWindows = mSettings->platform.isWindows();
@@ -625,11 +625,11 @@ void CheckIO::checkWrongPrintfScanfArguments()
     }
 }
 
-void CheckIO::checkFormatString(const Token * const tok,
-                                const Token * const formatStringTok,
-                                const Token *       argListTok,
-                                const bool scan,
-                                const bool scanf_s)
+void CheckIOImpl::checkFormatString(const Token * const tok,
+                                    const Token * const formatStringTok,
+                                    const Token *       argListTok,
+                                    const bool scan,
+                                    const bool scanf_s)
 {
     const bool isWindows = mSettings->platform.isWindows();
     const bool printWarning = mSettings->severity.isEnabled(Severity::warning);
@@ -1368,7 +1368,7 @@ void CheckIO::checkFormatString(const Token * const tok,
 // We currently only support string literals, variables, and functions.
 /// @todo add non-string literals, and generic expressions
 
-CheckIO::ArgumentInfo::ArgumentInfo(const Token * arg, const Settings &settings, bool _isCPP)
+CheckIOImpl::ArgumentInfo::ArgumentInfo(const Token * arg, const Settings &settings, bool _isCPP)
     : isCPP(_isCPP)
 {
     if (!arg)
@@ -1582,7 +1582,7 @@ CheckIO::ArgumentInfo::ArgumentInfo(const Token * arg, const Settings &settings,
     }
 }
 
-CheckIO::ArgumentInfo::~ArgumentInfo()
+CheckIOImpl::ArgumentInfo::~ArgumentInfo()
 {
     if (tempToken) {
         while (tempToken->next())
@@ -1597,7 +1597,7 @@ namespace {
     const std::set<std::string> stl_string = { "string", "u16string", "u32string", "wstring" };
 }
 
-bool CheckIO::ArgumentInfo::isStdVectorOrString()
+bool CheckIOImpl::ArgumentInfo::isStdVectorOrString()
 {
     if (!isCPP)
         return false;
@@ -1659,7 +1659,7 @@ static const std::set<std::string> stl_container = {
     "unordered_map", "unordered_multimap", "unordered_multiset", "unordered_set", "vector"
 };
 
-bool CheckIO::ArgumentInfo::isStdContainer(const Token *tok)
+bool CheckIOImpl::ArgumentInfo::isStdContainer(const Token *tok)
 {
     if (!isCPP)
         return false;
@@ -1691,7 +1691,7 @@ bool CheckIO::ArgumentInfo::isStdContainer(const Token *tok)
     return false;
 }
 
-bool CheckIO::ArgumentInfo::isArrayOrPointer() const
+bool CheckIOImpl::ArgumentInfo::isArrayOrPointer() const
 {
     if (address)
         return true;
@@ -1704,7 +1704,7 @@ bool CheckIO::ArgumentInfo::isArrayOrPointer() const
     return tok && tok->strAt(1) == "*";
 }
 
-bool CheckIO::ArgumentInfo::isComplexType() const
+bool CheckIOImpl::ArgumentInfo::isComplexType() const
 {
     if (variableInfo->type())
         return true;
@@ -1716,7 +1716,7 @@ bool CheckIO::ArgumentInfo::isComplexType() const
     return ((variableInfo->isStlStringType() || (varTypeTok->strAt(1) == "<" && varTypeTok->linkAt(1) && varTypeTok->linkAt(1)->strAt(1) != "::")) && !variableInfo->isArrayOrPointer());
 }
 
-bool CheckIO::ArgumentInfo::isKnownType() const
+bool CheckIOImpl::ArgumentInfo::isKnownType() const
 {
     if (variableInfo)
         return (typeToken->isStandardType() || typeToken->next()->isStandardType() || isComplexType());
@@ -1726,15 +1726,15 @@ bool CheckIO::ArgumentInfo::isKnownType() const
     return typeToken->isStandardType() || Token::Match(typeToken, "std :: string|wstring");
 }
 
-bool CheckIO::ArgumentInfo::isLibraryType(const Settings &settings) const
+bool CheckIOImpl::ArgumentInfo::isLibraryType(const Settings &settings) const
 {
     return typeToken && typeToken->isStandardType() && settings.library.podtype(typeToken->str());
 }
 
-void CheckIO::wrongPrintfScanfArgumentsError(const Token* tok,
-                                             const std::string &functionName,
-                                             nonneg int numFormat,
-                                             nonneg int numFunction)
+void CheckIOImpl::wrongPrintfScanfArgumentsError(const Token* tok,
+                                                 const std::string &functionName,
+                                                 nonneg int numFormat,
+                                                 nonneg int numFunction)
 {
     const Severity severity = numFormat > numFunction ? Severity::error : Severity::warning;
     if (severity != Severity::error && !mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("wrongPrintfScanfArgNum"))
@@ -1753,8 +1753,8 @@ void CheckIO::wrongPrintfScanfArgumentsError(const Token* tok,
     reportError(tok, severity, "wrongPrintfScanfArgNum", errmsg.str(), CWE685, Certainty::normal);
 }
 
-void CheckIO::wrongPrintfScanfPosixParameterPositionError(const Token* tok, const std::string& functionName,
-                                                          nonneg int index, nonneg int numFunction)
+void CheckIOImpl::wrongPrintfScanfPosixParameterPositionError(const Token* tok, const std::string& functionName,
+                                                              nonneg int index, nonneg int numFunction)
 {
     if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("wrongPrintfScanfParameterPositionError"))
         return;
@@ -1768,7 +1768,7 @@ void CheckIO::wrongPrintfScanfPosixParameterPositionError(const Token* tok, cons
     reportError(tok, Severity::warning, "wrongPrintfScanfParameterPositionError", errmsg.str(), CWE685, Certainty::normal);
 }
 
-void CheckIO::invalidScanfArgTypeError_s(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo)
+void CheckIOImpl::invalidScanfArgTypeError_s(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo)
 {
     const Severity severity = getSeverity(argInfo);
     if (!mSettings->severity.isEnabled(severity))
@@ -1784,7 +1784,7 @@ void CheckIO::invalidScanfArgTypeError_s(const Token* tok, nonneg int numFormat,
     errmsg << ".";
     reportError(tok, severity, "invalidScanfArgType_s", errmsg.str(), CWE686, Certainty::normal);
 }
-void CheckIO::invalidScanfArgTypeError_int(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo, bool isUnsigned)
+void CheckIOImpl::invalidScanfArgTypeError_int(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo, bool isUnsigned)
 {
     const Severity severity = getSeverity(argInfo);
     if (!mSettings->severity.isEnabled(severity))
@@ -1829,7 +1829,7 @@ void CheckIO::invalidScanfArgTypeError_int(const Token* tok, nonneg int numForma
     errmsg << ".";
     reportError(tok, severity, "invalidScanfArgType_int", errmsg.str(), CWE686, Certainty::normal);
 }
-void CheckIO::invalidScanfArgTypeError_float(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo)
+void CheckIOImpl::invalidScanfArgTypeError_float(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo)
 {
     const Severity severity = getSeverity(argInfo);
     if (!mSettings->severity.isEnabled(severity))
@@ -1848,7 +1848,7 @@ void CheckIO::invalidScanfArgTypeError_float(const Token* tok, nonneg int numFor
     reportError(tok, severity, "invalidScanfArgType_float", errmsg.str(), CWE686, Certainty::normal);
 }
 
-void CheckIO::invalidPrintfArgTypeError_s(const Token* tok, nonneg int numFormat, const ArgumentInfo* argInfo)
+void CheckIOImpl::invalidPrintfArgTypeError_s(const Token* tok, nonneg int numFormat, const ArgumentInfo* argInfo)
 {
     const Severity severity = getSeverity(argInfo);
     if (!mSettings->severity.isEnabled(severity))
@@ -1859,7 +1859,7 @@ void CheckIO::invalidPrintfArgTypeError_s(const Token* tok, nonneg int numFormat
     errmsg << ".";
     reportError(tok, severity, "invalidPrintfArgType_s", errmsg.str(), CWE686, Certainty::normal);
 }
-void CheckIO::invalidPrintfArgTypeError_n(const Token* tok, nonneg int numFormat, const ArgumentInfo* argInfo)
+void CheckIOImpl::invalidPrintfArgTypeError_n(const Token* tok, nonneg int numFormat, const ArgumentInfo* argInfo)
 {
     const Severity severity = getSeverity(argInfo);
     if (!mSettings->severity.isEnabled(severity))
@@ -1870,7 +1870,7 @@ void CheckIO::invalidPrintfArgTypeError_n(const Token* tok, nonneg int numFormat
     errmsg << ".";
     reportError(tok, severity, "invalidPrintfArgType_n", errmsg.str(), CWE686, Certainty::normal);
 }
-void CheckIO::invalidPrintfArgTypeError_p(const Token* tok, nonneg int numFormat, const ArgumentInfo* argInfo)
+void CheckIOImpl::invalidPrintfArgTypeError_p(const Token* tok, nonneg int numFormat, const ArgumentInfo* argInfo)
 {
     const Severity severity = getSeverity(argInfo);
     if (!mSettings->severity.isEnabled(severity))
@@ -1920,7 +1920,7 @@ static void printfFormatType(std::ostream& os, const std::string& specifier, boo
     os << "\'";
 }
 
-void CheckIO::invalidPrintfArgTypeError_uint(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo)
+void CheckIOImpl::invalidPrintfArgTypeError_uint(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo)
 {
     const Severity severity = getSeverity(argInfo);
     if (!mSettings->severity.isEnabled(severity))
@@ -1934,7 +1934,7 @@ void CheckIO::invalidPrintfArgTypeError_uint(const Token* tok, nonneg int numFor
     reportError(tok, severity, "invalidPrintfArgType_uint", errmsg.str(), CWE686, Certainty::normal);
 }
 
-void CheckIO::invalidPrintfArgTypeError_sint(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo)
+void CheckIOImpl::invalidPrintfArgTypeError_sint(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo)
 {
     const Severity severity = getSeverity(argInfo);
     if (!mSettings->severity.isEnabled(severity))
@@ -1947,7 +1947,7 @@ void CheckIO::invalidPrintfArgTypeError_sint(const Token* tok, nonneg int numFor
     errmsg << ".";
     reportError(tok, severity, "invalidPrintfArgType_sint", errmsg.str(), CWE686, Certainty::normal);
 }
-void CheckIO::invalidPrintfArgTypeError_float(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo)
+void CheckIOImpl::invalidPrintfArgTypeError_float(const Token* tok, nonneg int numFormat, const std::string& specifier, const ArgumentInfo* argInfo)
 {
     const Severity severity = getSeverity(argInfo);
     if (!mSettings->severity.isEnabled(severity))
@@ -1962,12 +1962,12 @@ void CheckIO::invalidPrintfArgTypeError_float(const Token* tok, nonneg int numFo
     reportError(tok, severity, "invalidPrintfArgType_float", errmsg.str(), CWE686, Certainty::normal);
 }
 
-Severity CheckIO::getSeverity(const CheckIO::ArgumentInfo *argInfo)
+Severity CheckIOImpl::getSeverity(const ArgumentInfo *argInfo)
 {
     return (argInfo && argInfo->typeToken && !argInfo->typeToken->originalName().empty()) ? Severity::portability : Severity::warning;
 }
 
-void CheckIO::argumentType(std::ostream& os, const ArgumentInfo * argInfo)
+void CheckIOImpl::argumentType(std::ostream& os, const ArgumentInfo * argInfo)
 {
     if (argInfo) {
         os << "\'";
@@ -2017,7 +2017,7 @@ void CheckIO::argumentType(std::ostream& os, const ArgumentInfo * argInfo)
         os << "Unknown";
 }
 
-void CheckIO::invalidLengthModifierError(const Token* tok, nonneg int numFormat, const std::string& modifier)
+void CheckIOImpl::invalidLengthModifierError(const Token* tok, nonneg int numFormat, const std::string& modifier)
 {
     if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("invalidLengthModifierError"))
         return;
@@ -2026,7 +2026,7 @@ void CheckIO::invalidLengthModifierError(const Token* tok, nonneg int numFormat,
     reportError(tok, Severity::warning, "invalidLengthModifierError", errmsg.str(), CWE704, Certainty::normal);
 }
 
-void CheckIO::invalidScanfFormatWidthError(const Token* tok, nonneg int numFormat, int width, const Variable *var, const std::string& specifier)
+void CheckIOImpl::invalidScanfFormatWidthError(const Token* tok, nonneg int numFormat, int width, const Variable *var, const std::string& specifier)
 {
     MathLib::bigint arrlen = 0;
     std::string varname;
@@ -2052,7 +2052,7 @@ void CheckIO::invalidScanfFormatWidthError(const Token* tok, nonneg int numForma
 
 void CheckIO::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    CheckIO checkIO(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckIOImpl checkIO(&tokenizer, &tokenizer.getSettings(), errorLogger);
 
     checkIO.checkWrongPrintfScanfArguments();
     checkIO.checkCoutCerrMisusage();
@@ -2062,7 +2062,7 @@ void CheckIO::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 
 void CheckIO::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckIO c(nullptr, settings, errorLogger);
+    CheckIOImpl c(nullptr, settings, errorLogger);
     c.coutCerrMisusageError(nullptr,  "cout");
     c.fflushOnInputStreamError(nullptr,  "stdin");
     c.ioWithoutPositioningError(nullptr);
diff --git a/lib/checkio.h b/lib/checkio.h
index b3c86da3577..acad40de136 100644
--- a/lib/checkio.h
+++ b/lib/checkio.h
@@ -22,6 +22,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <cstdint>
@@ -45,16 +46,35 @@ class CPPCHECKLIB CheckIO : public Check {
 
 public:
     /** @brief This constructor is used when registering CheckIO */
-    CheckIO() : Check(myName()) {}
+    CheckIO() : Check("IO using format string") {}
 
 private:
-    /** @brief This constructor is used when running checks. */
-    CheckIO(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     /** @brief Run checks on the normal token list */
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+
+    std::string classInfo() const override {
+        return "Check format string input/output operations.\n"
+               "- Bad usage of the function 'sprintf' (overlapping data)\n"
+               "- Missing or wrong width specifiers in 'scanf' format string\n"
+               "- Use a file that has been closed\n"
+               "- File input/output without positioning results in undefined behaviour\n"
+               "- Read to a file that has only been opened for writing (or vice versa)\n"
+               "- Repositioning operation on a file opened in append mode\n"
+               "- The same file can't be open for read and write at the same time on different streams\n"
+               "- Using fflush() on an input stream\n"
+               "- Invalid usage of output stream. For example: 'std::cout << std::cout;'\n"
+               "- Wrong number of arguments given to 'printf' or 'scanf;'\n";
+    }
+};
+
+class CPPCHECKLIB CheckIOImpl : public CheckImpl {
+public:
+    /** @brief This constructor is used when running checks. */
+    CheckIOImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     /** @brief %Check for missusage of std::cout */
     void checkCoutCerrMisusage();
 
@@ -128,26 +148,6 @@ class CPPCHECKLIB CheckIO : public Check {
     void invalidScanfFormatWidthError(const Token* tok, nonneg int numFormat, int width, const Variable *var, const std::string& specifier);
     static void argumentType(std::ostream & os, const ArgumentInfo * argInfo);
     static Severity getSeverity(const ArgumentInfo *argInfo);
-
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "IO using format string";
-    }
-
-    std::string classInfo() const override {
-        return "Check format string input/output operations.\n"
-               "- Bad usage of the function 'sprintf' (overlapping data)\n"
-               "- Missing or wrong width specifiers in 'scanf' format string\n"
-               "- Use a file that has been closed\n"
-               "- File input/output without positioning results in undefined behaviour\n"
-               "- Read to a file that has only been opened for writing (or vice versa)\n"
-               "- Repositioning operation on a file opened in append mode\n"
-               "- The same file can't be open for read and write at the same time on different streams\n"
-               "- Using fflush() on an input stream\n"
-               "- Invalid usage of output stream. For example: 'std::cout << std::cout;'\n"
-               "- Wrong number of arguments given to 'printf' or 'scanf;'\n";
-    }
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp
index 1c9a7283161..e0ec6801255 100644
--- a/lib/checkleakautovar.cpp
+++ b/lib/checkleakautovar.cpp
@@ -107,35 +107,35 @@ void VarInfo::possibleUsageAll(const std::pair<const Token*, Usage>& functionUsa
 }
 
 
-void CheckLeakAutoVar::leakError(const Token *tok, const std::string &varname, int type) const
+void CheckLeakAutoVarImpl::leakError(const Token *tok, const std::string &varname, int type) const
 {
-    const CheckMemoryLeak checkmemleak(mTokenizer, mErrorLogger, mSettings);
+    const CheckMemoryLeakImpl checkmemleak(mTokenizer, mSettings, mErrorLogger);
     if (Library::isresource(type))
         checkmemleak.resourceLeakError(tok, varname);
     else
         checkmemleak.memleakError(tok, varname);
 }
 
-void CheckLeakAutoVar::mismatchError(const Token *deallocTok, const Token *allocTok, const std::string &varname) const
+void CheckLeakAutoVarImpl::mismatchError(const Token *deallocTok, const Token *allocTok, const std::string &varname) const
 {
-    const CheckMemoryLeak c(mTokenizer, mErrorLogger, mSettings);
+    const CheckMemoryLeakImpl c(mTokenizer, mSettings, mErrorLogger);
     const std::list<const Token *> callstack = { allocTok, deallocTok };
     c.mismatchAllocDealloc(callstack, varname);
 }
 
-void CheckLeakAutoVar::deallocUseError(const Token *tok, const std::string &varname) const
+void CheckLeakAutoVarImpl::deallocUseError(const Token *tok, const std::string &varname) const
 {
-    const CheckMemoryLeak c(mTokenizer, mErrorLogger, mSettings);
+    const CheckMemoryLeakImpl c(mTokenizer, mSettings, mErrorLogger);
     c.deallocuseError(tok, varname);
 }
 
-void CheckLeakAutoVar::deallocReturnError(const Token *tok, const Token *deallocTok, const std::string &varname)
+void CheckLeakAutoVarImpl::deallocReturnError(const Token *tok, const Token *deallocTok, const std::string &varname)
 {
     const std::list<const Token *> locations = { deallocTok, tok };
     reportError(locations, Severity::error, "deallocret", "$symbol:" + varname + "\nReturning/dereferencing '$symbol' after it is deallocated / released", CWE672, Certainty::normal);
 }
 
-void CheckLeakAutoVar::configurationInfo(const Token* tok, const std::pair<const Token*, VarInfo::Usage>& functionUsage)
+void CheckLeakAutoVarImpl::configurationInfo(const Token* tok, const std::pair<const Token*, VarInfo::Usage>& functionUsage)
 {
     if (mSettings->checkLibrary && functionUsage.second == VarInfo::USED &&
         (!functionUsage.first || !functionUsage.first->function() || !functionUsage.first->function()->hasBody())) {
@@ -149,7 +149,7 @@ void CheckLeakAutoVar::configurationInfo(const Token* tok, const std::pair<const
     }
 }
 
-void CheckLeakAutoVar::doubleFreeError(const Token *tok, const Token *prevFreeTok, const std::string &varname, int type)
+void CheckLeakAutoVarImpl::doubleFreeError(const Token *tok, const Token *prevFreeTok, const std::string &varname, int type)
 {
     const std::list<const Token *> locations = { prevFreeTok, tok };
 
@@ -160,7 +160,7 @@ void CheckLeakAutoVar::doubleFreeError(const Token *tok, const Token *prevFreeTo
 }
 
 
-void CheckLeakAutoVar::check()
+void CheckLeakAutoVarImpl::check()
 {
     if (mSettings->clang)
         return;
@@ -303,10 +303,10 @@ static std::vector<const Token*> getComparisonTokens(const Token* tok)
     return result;
 }
 
-bool CheckLeakAutoVar::checkScope(const Token * const startToken,
-                                  VarInfo &varInfo,
-                                  std::set<int> notzero,
-                                  nonneg int recursiveCount)
+bool CheckLeakAutoVarImpl::checkScope(const Token * const startToken,
+                                      VarInfo &varInfo,
+                                      std::set<int> notzero,
+                                      nonneg int recursiveCount)
 {
 #if ASAN
     static const nonneg int recursiveLimit = 300;
@@ -887,7 +887,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken,
 }
 
 
-const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const tok, VarInfo &varInfo, bool inFuncCall)
+const Token * CheckLeakAutoVarImpl::checkTokenInsideExpression(const Token * const tok, VarInfo &varInfo, bool inFuncCall)
 {
     // Deallocation and then dereferencing pointer..
     if (tok->varId() > 0) {
@@ -956,7 +956,7 @@ const Token * CheckLeakAutoVar::checkTokenInsideExpression(const Token * const t
 }
 
 
-void CheckLeakAutoVar::changeAllocStatusIfRealloc(std::map<int, VarInfo::AllocInfo> &alloctype, const Token *fTok, const Token *retTok) const
+void CheckLeakAutoVarImpl::changeAllocStatusIfRealloc(std::map<int, VarInfo::AllocInfo> &alloctype, const Token *fTok, const Token *retTok) const
 {
     const Library::AllocFunc* f = mSettings->library.getReallocFuncInfo(fTok);
     if (f && f->arg == -1 && f->reallocArg > 0 && f->reallocArg <= numberOfArguments(fTok)) {
@@ -977,7 +977,7 @@ void CheckLeakAutoVar::changeAllocStatusIfRealloc(std::map<int, VarInfo::AllocIn
 }
 
 
-void CheckLeakAutoVar::changeAllocStatus(VarInfo &varInfo, const VarInfo::AllocInfo& allocation, const Token* tok, const Token* arg)
+void CheckLeakAutoVarImpl::changeAllocStatus(VarInfo &varInfo, const VarInfo::AllocInfo& allocation, const Token* tok, const Token* arg)
 {
     std::map<int, VarInfo::AllocInfo> &alloctype = varInfo.alloctype;
     const auto var = alloctype.find(arg->varId());
@@ -1014,7 +1014,7 @@ void CheckLeakAutoVar::changeAllocStatus(VarInfo &varInfo, const VarInfo::AllocI
     }
 }
 
-void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpeningPar, VarInfo &varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af)
+void CheckLeakAutoVarImpl::functionCall(const Token *tokName, const Token *tokOpeningPar, VarInfo &varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af)
 {
     // Ignore function call?
     const bool isLeakIgnore = mSettings->library.isLeakIgnore(mSettings->library.getFunctionName(tokName));
@@ -1153,8 +1153,8 @@ void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpenin
 }
 
 
-void CheckLeakAutoVar::leakIfAllocated(const Token *vartok,
-                                       const VarInfo &varInfo)
+void CheckLeakAutoVarImpl::leakIfAllocated(const Token *vartok,
+                                           const VarInfo &varInfo)
 {
     const std::map<int, VarInfo::AllocInfo> &alloctype = varInfo.alloctype;
     const auto& possibleUsage = varInfo.possibleUsage;
@@ -1176,7 +1176,7 @@ static bool isSafeCast(const ValueType* vt, const Settings& settings)
     return sizeOf == 0 || sizeOf >= settings.platform.sizeof_pointer;
 }
 
-void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndOfScope)
+void CheckLeakAutoVarImpl::ret(const Token *tok, VarInfo &varInfo, const bool isEndOfScope)
 {
     const std::map<int, VarInfo::AllocInfo> &alloctype = varInfo.alloctype;
     const auto& possibleUsage = varInfo.possibleUsage;
@@ -1280,13 +1280,13 @@ void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndO
 
 void CheckLeakAutoVar::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    CheckLeakAutoVar checkLeakAutoVar(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckLeakAutoVarImpl checkLeakAutoVar(&tokenizer, &tokenizer.getSettings(), errorLogger);
     checkLeakAutoVar.check();
 }
 
 void CheckLeakAutoVar::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckLeakAutoVar c(nullptr, settings, errorLogger);
+    CheckLeakAutoVarImpl c(nullptr, settings, errorLogger);
     c.deallocReturnError(nullptr, nullptr, "p");
     c.configurationInfo(nullptr, { nullptr, VarInfo::USED });  // user configuration is needed to complete analysis
     c.doubleFreeError(nullptr, nullptr, "varname", 0);
diff --git a/lib/checkleakautovar.h b/lib/checkleakautovar.h
index d7d8d390b3d..ce7e1ddbd8b 100644
--- a/lib/checkleakautovar.h
+++ b/lib/checkleakautovar.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 #include "library.h"
 
@@ -107,15 +108,24 @@ class CPPCHECKLIB VarInfo {
 class CPPCHECKLIB CheckLeakAutoVar : public Check {
 public:
     /** This constructor is used when registering the CheckLeakAutoVar */
-    CheckLeakAutoVar() : Check(myName()) {}
+    CheckLeakAutoVar() : Check("Leaks (auto variables)") {}
 
 private:
-    /** This constructor is used when running checks. */
-    CheckLeakAutoVar(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+
+    std::string classInfo() const override {
+        return "Detect when a auto variable is allocated but not deallocated or deallocated twice.\n";
+    }
+};
+
+class CPPCHECKLIB CheckLeakAutoVarImpl : public CheckImpl {
+public:
+    /** This constructor is used when running checks. */
+    CheckLeakAutoVarImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     /** check for leaks in all scopes */
     void check();
 
@@ -157,16 +167,6 @@ class CPPCHECKLIB CheckLeakAutoVar : public Check {
 
     /** message: user configuration is needed to complete analysis */
     void configurationInfo(const Token* tok, const std::pair<const Token*, VarInfo::Usage>& functionUsage);
-
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "Leaks (auto variables)";
-    }
-
-    std::string classInfo() const override {
-        return "Detect when a auto variable is allocated but not deallocated or deallocated twice.\n";
-    }
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp
index b2f97693cd6..e90ed552426 100644
--- a/lib/checkmemoryleak.cpp
+++ b/lib/checkmemoryleak.cpp
@@ -31,6 +31,7 @@
 #include "utils.h"
 
 #include <algorithm>
+#include <cassert>
 #include <cstddef>
 #include <utility>
 #include <vector>
@@ -45,7 +46,8 @@ static const CWE CWE772(772U);  // Missing Release of Resource after Effective L
 
 //---------------------------------------------------------------------------
 
-CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2, nonneg int varid, std::list<const Function*> *callstack) const
+
+CheckMemoryLeakImpl::AllocType CheckMemoryLeakImpl::getAllocationType(const Token *tok2, nonneg int varid, std::list<const Function*> *callstack) const
 {
     // What we may have...
     //     * var = (char *)malloc(10);
@@ -93,7 +95,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2,
             return New;
         }
 
-        if (mSettings_->hasLib("posix")) {
+        if (mSettings->hasLib("posix")) {
             if (Token::Match(tok2, "open|openat|creat|mkstemp|mkostemp|socket (")) {
                 // simple sanity check of function parameters..
                 // TODO: Make such check for all these functions
@@ -112,11 +114,11 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2,
         }
 
         // Does tok2 point on a Library allocation function?
-        const int alloctype = mSettings_->library.getAllocId(tok2, -1);
+        const int alloctype = mSettings->library.getAllocId(tok2, -1);
         if (alloctype > 0) {
-            if (alloctype == mSettings_->library.deallocId("free"))
+            if (alloctype == mSettings->library.deallocId("free"))
                 return Malloc;
-            if (alloctype == mSettings_->library.deallocId("fclose"))
+            if (alloctype == mSettings->library.deallocId("fclose"))
                 return File;
             return Library::ismemory(alloctype) ? OtherMem : OtherRes;
         }
@@ -143,7 +145,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getAllocationType(const Token *tok2,
 }
 
 
-CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok2, nonneg int varid) const
+CheckMemoryLeakImpl::AllocType CheckMemoryLeakImpl::getReallocationType(const Token *tok2, nonneg int varid) const
 {
     // What we may have...
     //     * var = (char *)realloc(..;
@@ -157,7 +159,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok
     if (!Token::Match(tok2, "%name% ("))
         return No;
 
-    const Library::AllocFunc *f = mSettings_->library.getReallocFuncInfo(tok2);
+    const Library::AllocFunc *f = mSettings->library.getReallocFuncInfo(tok2);
     if (!(f && f->reallocArg > 0 && f->reallocArg <= numberOfArguments(tok2)))
         return No;
     const auto args = getArguments(tok2);
@@ -171,11 +173,11 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok
     if (varid > 0 && !Token::Match(arg, "%varid% [,)]", varid))
         return No;
 
-    const int realloctype = mSettings_->library.getReallocId(tok2, -1);
+    const int realloctype = mSettings->library.getReallocId(tok2, -1);
     if (realloctype > 0) {
-        if (realloctype == mSettings_->library.deallocId("free"))
+        if (realloctype == mSettings->library.deallocId("free"))
             return Malloc;
-        if (realloctype == mSettings_->library.deallocId("fclose"))
+        if (realloctype == mSettings->library.deallocId("fclose"))
             return File;
         return Library::ismemory(realloctype) ? OtherMem : OtherRes;
     }
@@ -183,7 +185,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getReallocationType(const Token *tok
 }
 
 
-CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok, nonneg int varid) const
+CheckMemoryLeakImpl::AllocType CheckMemoryLeakImpl::getDeallocationType(const Token *tok, nonneg int varid) const
 {
     if (tok->isCpp() && tok->str() == "delete" && tok->astOperand1()) {
         const Token* vartok = tok->astOperand1();
@@ -214,7 +216,7 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok
                 if (tok->str() == "realloc" && Token::simpleMatch(vartok->next(), ", 0 )"))
                     return Malloc;
 
-                if (mSettings_->hasLib("posix")) {
+                if (mSettings->hasLib("posix")) {
                     if (tok->str() == "close")
                         return Fd;
                     if (tok->str() == "pclose")
@@ -222,11 +224,11 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok
                 }
 
                 // Does tok point on a Library deallocation function?
-                const int dealloctype = mSettings_->library.getDeallocId(tok, argNr);
+                const int dealloctype = mSettings->library.getDeallocId(tok, argNr);
                 if (dealloctype > 0) {
-                    if (dealloctype == mSettings_->library.deallocId("free"))
+                    if (dealloctype == mSettings->library.deallocId("free"))
                         return Malloc;
-                    if (dealloctype == mSettings_->library.deallocId("fclose"))
+                    if (dealloctype == mSettings->library.deallocId("fclose"))
                         return File;
                     return Library::ismemory(dealloctype) ? OtherMem : OtherRes;
                 }
@@ -238,10 +240,10 @@ CheckMemoryLeak::AllocType CheckMemoryLeak::getDeallocationType(const Token *tok
     return No;
 }
 
-bool CheckMemoryLeak::isReopenStandardStream(const Token *tok) const
+bool CheckMemoryLeakImpl::isReopenStandardStream(const Token *tok) const
 {
     if (getReallocationType(tok, 0) == File) {
-        const Library::AllocFunc *f = mSettings_->library.getReallocFuncInfo(tok);
+        const Library::AllocFunc *f = mSettings->library.getReallocFuncInfo(tok);
         if (f && f->reallocArg > 0 && f->reallocArg <= numberOfArguments(tok)) {
             const Token* arg = getArguments(tok).at(f->reallocArg - 1);
             if (Token::Match(arg, "stdin|stdout|stderr"))
@@ -251,9 +253,9 @@ bool CheckMemoryLeak::isReopenStandardStream(const Token *tok) const
     return false;
 }
 
-bool CheckMemoryLeak::isOpenDevNull(const Token *tok) const
+bool CheckMemoryLeakImpl::isOpenDevNull(const Token *tok) const
 {
-    if (mSettings_->hasLib("posix") && tok->str() == "open" && numberOfArguments(tok) == 2) {
+    if (mSettings->hasLib("posix") && tok->str() == "open" && numberOfArguments(tok) == 2) {
         const Token* arg = getArguments(tok).at(0);
         if (Token::simpleMatch(arg, "\"/dev/null\""))
             return true;
@@ -261,24 +263,18 @@ bool CheckMemoryLeak::isOpenDevNull(const Token *tok) const
     return false;
 }
 
-//--------------------------------------------------------------------------
-
-
-//--------------------------------------------------------------------------
-
-void CheckMemoryLeak::memoryLeak(const Token *tok, const std::string &varname, AllocType alloctype) const
+void CheckMemoryLeakImpl::memoryLeak(const Token *tok, const std::string &varname, AllocType alloctype) const
 {
-    if (alloctype == CheckMemoryLeak::File ||
-        alloctype == CheckMemoryLeak::Pipe ||
-        alloctype == CheckMemoryLeak::Fd ||
-        alloctype == CheckMemoryLeak::OtherRes)
+    if (alloctype == File ||
+        alloctype == Pipe ||
+        alloctype == Fd ||
+        alloctype == OtherRes)
         resourceLeakError(tok, varname);
     else
         memleakError(tok, varname);
 }
-//---------------------------------------------------------------------------
 
-void CheckMemoryLeak::reportErr(const Token *tok, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const
+void CheckMemoryLeakImpl::reportErr(const Token *tok, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const
 {
     std::list<const Token *> callstack;
 
@@ -288,26 +284,26 @@ void CheckMemoryLeak::reportErr(const Token *tok, Severity severity, const std::
     reportErr(callstack, severity, id, msg, cwe);
 }
 
-void CheckMemoryLeak::reportErr(const std::list<const Token *> &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const
+void CheckMemoryLeakImpl::reportErr(const std::list<const Token *> &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const
 {
-    const ErrorMessage errmsg(callstack, mTokenizer_ ? &mTokenizer_->list : nullptr, severity, id, msg, cwe, Certainty::normal);
-    if (mErrorLogger_)
-        mErrorLogger_->reportErr(errmsg);
-    else
-        Check::writeToErrorList(errmsg);
+    if (!mErrorLogger)
+        assert(false);
+
+    const ErrorMessage errmsg(callstack, mTokenizer ? &mTokenizer->list : nullptr, severity, id, msg, cwe, Certainty::normal);
+    mErrorLogger->reportErr(errmsg);
 }
 
-void CheckMemoryLeak::memleakError(const Token *tok, const std::string &varname) const
+void CheckMemoryLeakImpl::memleakError(const Token *tok, const std::string &varname) const
 {
     reportErr(tok, Severity::error, "memleak", "$symbol:" + varname + "\nMemory leak: $symbol", CWE(401U));
 }
 
-void CheckMemoryLeak::memleakUponReallocFailureError(const Token *tok, const std::string &reallocfunction, const std::string &varname) const
+void CheckMemoryLeakImpl::memleakUponReallocFailureError(const Token *tok, const std::string &reallocfunction, const std::string &varname) const
 {
     reportErr(tok, Severity::error, "memleakOnRealloc", "$symbol:" + varname + "\nCommon " + reallocfunction + " mistake: \'$symbol\' nulled but not freed upon failure", CWE(401U));
 }
 
-void CheckMemoryLeak::resourceLeakError(const Token *tok, const std::string &varname) const
+void CheckMemoryLeakImpl::resourceLeakError(const Token *tok, const std::string &varname) const
 {
     std::string errmsg("Resource leak");
     if (!varname.empty())
@@ -315,17 +311,17 @@ void CheckMemoryLeak::resourceLeakError(const Token *tok, const std::string &var
     reportErr(tok, Severity::error, "resourceLeak", errmsg, CWE(775U));
 }
 
-void CheckMemoryLeak::deallocuseError(const Token *tok, const std::string &varname) const
+void CheckMemoryLeakImpl::deallocuseError(const Token *tok, const std::string &varname) const
 {
     reportErr(tok, Severity::error, "deallocuse", "$symbol:" + varname + "\nDereferencing '$symbol' after it is deallocated / released", CWE(416U));
 }
 
-void CheckMemoryLeak::mismatchAllocDealloc(const std::list<const Token *> &callstack, const std::string &varname) const
+void CheckMemoryLeakImpl::mismatchAllocDealloc(const std::list<const Token *> &callstack, const std::string &varname) const
 {
     reportErr(callstack, Severity::error, "mismatchAllocDealloc", "$symbol:" + varname + "\nMismatching allocation and deallocation: $symbol", CWE(762U));
 }
 
-CheckMemoryLeak::AllocType CheckMemoryLeak::functionReturnType(const Function* func, std::list<const Function*> *callstack) const
+CheckMemoryLeakImpl::AllocType CheckMemoryLeakImpl::functionReturnType(const Function* func, std::list<const Function*> *callstack) const
 {
     if (!func || !func->hasBody() || !func->functionScope)
         return No;
@@ -423,7 +419,7 @@ static bool ifvar(const Token *tok, nonneg int varid, const std::string &comp, c
 //     a = malloc(10); a = realloc(a, 100);
 //---------------------------------------------------------------------------
 
-void CheckMemoryLeakInFunction::checkReallocUsage()
+void CheckMemoryLeakInFunctionImpl::checkReallocUsage()
 {
     logChecker("CheckMemoryLeakInFunction::checkReallocUsage");
 
@@ -494,17 +490,15 @@ void CheckMemoryLeakInFunction::checkReallocUsage()
         }
     }
 }
-//---------------------------------------------------------------------------
 
-void CheckMemoryLeakInFunction::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
-{
-    CheckMemoryLeakInFunction checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger);
+void CheckMemoryLeakInFunction::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) {
+    CheckMemoryLeakInFunctionImpl checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger);
     checkMemoryLeak.checkReallocUsage();
 }
 
-void CheckMemoryLeakInFunction::getErrorMessages(ErrorLogger *e, const Settings *settings) const
-{
-    CheckMemoryLeakInFunction c(nullptr, settings, e);
+/** Report all possible errors (for the --errorlist) */
+void CheckMemoryLeakInFunction::getErrorMessages(ErrorLogger *e, const Settings *settings) const {
+    CheckMemoryLeakInFunctionImpl c(nullptr, settings, e);
     c.memleakError(nullptr, "varname");
     c.resourceLeakError(nullptr, "varname");
     c.deallocuseError(nullptr, "varname");
@@ -517,8 +511,7 @@ void CheckMemoryLeakInFunction::getErrorMessages(ErrorLogger *e, const Settings
 // Checks for memory leaks in classes..
 //---------------------------------------------------------------------------
 
-
-void CheckMemoryLeakInClass::check()
+void CheckMemoryLeakInClassImpl::check()
 {
     logChecker("CheckMemoryLeakInClass::check");
 
@@ -543,15 +536,15 @@ void CheckMemoryLeakInClass::check()
 }
 
 
-void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarname)
+void CheckMemoryLeakInClassImpl::variable(const Scope *scope, const Token *tokVarname)
 {
     const std::string& varname = tokVarname->str();
     const int varid = tokVarname->varId();
     const std::string& classname = scope->className;
 
     // Check if member variable has been allocated and deallocated..
-    CheckMemoryLeak::AllocType memberAlloc = CheckMemoryLeak::No;
-    CheckMemoryLeak::AllocType memberDealloc = CheckMemoryLeak::No;
+    AllocType memberAlloc = AllocType::No;
+    AllocType memberDealloc = AllocType::No;
 
     bool allocInConstructor = false;
     bool deallocInDestructor = false;
@@ -563,7 +556,7 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam
         if (!func.hasBody()) {
             if (destructor && !func.isDefault()) { // implementation for destructor is not seen and not defaulted => assume it deallocates all variables properly
                 deallocInDestructor = true;
-                memberDealloc = CheckMemoryLeak::Many;
+                memberDealloc = AllocType::Many;
             }
             continue;
         }
@@ -596,14 +589,14 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam
                         allocTok = tok->astParent()->astParent()->astOperand2();
 
                     AllocType alloc = getAllocationType(allocTok, 0);
-                    if (alloc != CheckMemoryLeak::No) {
+                    if (alloc != AllocType::No) {
                         if (constructor)
                             allocInConstructor = true;
 
-                        if (memberAlloc != No && memberAlloc != alloc)
-                            alloc = CheckMemoryLeak::Many;
+                        if (memberAlloc != AllocType::No && memberAlloc != alloc)
+                            alloc = AllocType::Many;
 
-                        if (alloc != CheckMemoryLeak::Many && memberDealloc != CheckMemoryLeak::No && memberDealloc != CheckMemoryLeak::Many && memberDealloc != alloc) {
+                        if (alloc != AllocType::Many && memberDealloc != AllocType::No && memberDealloc != AllocType::Many && memberDealloc != alloc) {
                             mismatchAllocDealloc({tok}, classname + "::" + varname);
                         }
 
@@ -619,18 +612,18 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam
                 // some usage in the destructor => assume it's related
                 // to deallocation
                 if (destructor && tok->str() == varname)
-                    dealloc = CheckMemoryLeak::Many;
-                if (dealloc != CheckMemoryLeak::No) {
+                    dealloc = AllocType::Many;
+                if (dealloc != AllocType::No) {
                     if (destructor)
                         deallocInDestructor = true;
 
-                    if (dealloc != CheckMemoryLeak::Many && memberAlloc != CheckMemoryLeak::No && memberAlloc != Many && memberAlloc != dealloc) {
+                    if (dealloc != AllocType::Many && memberAlloc != AllocType::No && memberAlloc != Many && memberAlloc != dealloc) {
                         mismatchAllocDealloc({tok}, classname + "::" + varname);
                     }
 
                     // several types of allocation/deallocation?
-                    if (memberDealloc != CheckMemoryLeak::No && memberDealloc != dealloc)
-                        dealloc = CheckMemoryLeak::Many;
+                    if (memberDealloc != AllocType::No && memberDealloc != dealloc)
+                        dealloc = AllocType::Many;
 
                     memberDealloc = dealloc;
                 }
@@ -645,12 +638,12 @@ void CheckMemoryLeakInClass::variable(const Scope *scope, const Token *tokVarnam
 
     if (allocInConstructor && !deallocInDestructor) {
         unsafeClassError(tokVarname, classname, classname + "::" + varname /*, memberAlloc*/);
-    } else if (memberAlloc != CheckMemoryLeak::No && memberDealloc == CheckMemoryLeak::No) {
+    } else if (memberAlloc != AllocType::No && memberDealloc == AllocType::No) {
         unsafeClassError(tokVarname, classname, classname + "::" + varname /*, memberAlloc*/);
     }
 }
 
-void CheckMemoryLeakInClass::unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname)
+void CheckMemoryLeakInClassImpl::unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname)
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unsafeClassCanLeak"))
         return;
@@ -663,7 +656,7 @@ void CheckMemoryLeakInClass::unsafeClassError(const Token *tok, const std::strin
 }
 
 
-void CheckMemoryLeakInClass::checkPublicFunctions(const Scope *scope, const Token *classtok)
+void CheckMemoryLeakInClassImpl::checkPublicFunctions(const Scope *scope, const Token *classtok)
 {
     // Check that public functions deallocate the pointers that they allocate.
     // There is no checking how these functions are used and therefore it
@@ -680,20 +673,20 @@ void CheckMemoryLeakInClass::checkPublicFunctions(const Scope *scope, const Toke
             func.access == AccessControl::Public && func.hasBody()) {
             const Token *tok2 = func.functionScope->bodyStart->next();
             if (Token::Match(tok2, "%varid% =", varid)) {
-                const CheckMemoryLeak::AllocType alloc = getAllocationType(tok2->tokAt(2), varid);
-                if (alloc != CheckMemoryLeak::No)
+                const AllocType alloc = getAllocationType(tok2->tokAt(2), varid);
+                if (alloc != AllocType::No)
                     publicAllocationError(tok2, tok2->str());
             } else if (Token::Match(tok2, "%type% :: %varid% =", varid) &&
                        tok2->str() == scope->className) {
-                const CheckMemoryLeak::AllocType alloc = getAllocationType(tok2->tokAt(4), varid);
-                if (alloc != CheckMemoryLeak::No)
+                const AllocType alloc = getAllocationType(tok2->tokAt(4), varid);
+                if (alloc != AllocType::No)
                     publicAllocationError(tok2, tok2->strAt(2));
             }
         }
     }
 }
 
-void CheckMemoryLeakInClass::publicAllocationError(const Token *tok, const std::string &varname)
+void CheckMemoryLeakInClassImpl::publicAllocationError(const Token *tok, const std::string &varname)
 {
     reportError(tok, Severity::warning, "publicAllocationError", "$symbol:" + varname + "\nPossible leak in public function. The pointer '$symbol' is not deallocated before it is allocated.", CWE398, Certainty::normal);
 }
@@ -703,19 +696,18 @@ void CheckMemoryLeakInClass::runChecks(const Tokenizer &tokenizer, ErrorLogger *
     if (!tokenizer.isCPP())
         return;
 
-    CheckMemoryLeakInClass checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckMemoryLeakInClassImpl checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger);
     checkMemoryLeak.check();
 }
 
 void CheckMemoryLeakInClass::getErrorMessages(ErrorLogger *e, const Settings *settings) const
 {
-    CheckMemoryLeakInClass c(nullptr, settings, e);
+    CheckMemoryLeakInClassImpl c(nullptr, settings, e);
     c.publicAllocationError(nullptr, "varname");
     c.unsafeClassError(nullptr, "class", "class::varname");
 }
 
-
-void CheckMemoryLeakStructMember::check()
+void CheckMemoryLeakStructMemberImpl::check()
 {
     if (mSettings->clang)
         return;
@@ -734,7 +726,7 @@ void CheckMemoryLeakStructMember::check()
     }
 }
 
-bool CheckMemoryLeakStructMember::isMalloc(const Variable *variable) const
+bool CheckMemoryLeakStructMemberImpl::isMalloc(const Variable *variable) const
 {
     if (!variable)
         return false;
@@ -756,7 +748,7 @@ bool CheckMemoryLeakStructMember::isMalloc(const Variable *variable) const
     return alloc;
 }
 
-void CheckMemoryLeakStructMember::checkStructVariable(const Variable* const variable) const
+void CheckMemoryLeakStructMemberImpl::checkStructVariable(const Variable* const variable) const
 {
     if (!variable)
         return;
@@ -976,15 +968,11 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable* const vari
 
 void CheckMemoryLeakStructMember::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    CheckMemoryLeakStructMember checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckMemoryLeakStructMemberImpl checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger);
     checkMemoryLeak.check();
 }
 
-void CheckMemoryLeakStructMember::getErrorMessages(ErrorLogger * /*errorLogger*/, const Settings * /*settings*/) const
-{}
-
-
-void CheckMemoryLeakNoVar::check()
+void CheckMemoryLeakNoVarImpl::check()
 {
     logChecker("CheckMemoryLeakNoVar::check");
 
@@ -1010,7 +998,7 @@ void CheckMemoryLeakNoVar::check()
 // Checks if an input argument to a function is the return value of an allocation function
 // like malloc(), and the function does not release it.
 //---------------------------------------------------------------------------
-void CheckMemoryLeakNoVar::checkForUnreleasedInputArgument(const Scope *scope)
+void CheckMemoryLeakNoVarImpl::checkForUnreleasedInputArgument(const Scope *scope)
 {
     // parse the executable scope until tok is reached...
     for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
@@ -1083,7 +1071,7 @@ void CheckMemoryLeakNoVar::checkForUnreleasedInputArgument(const Scope *scope)
 //---------------------------------------------------------------------------
 // Checks if a call to an allocation function like malloc() is made and its return value is not assigned.
 //---------------------------------------------------------------------------
-void CheckMemoryLeakNoVar::checkForUnusedReturnValue(const Scope *scope)
+void CheckMemoryLeakNoVarImpl::checkForUnusedReturnValue(const Scope *scope)
 {
     for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
         const bool isNew = tok->isCpp() && tok->str() == "new";
@@ -1150,7 +1138,7 @@ void CheckMemoryLeakNoVar::checkForUnusedReturnValue(const Scope *scope)
 //    f(shared_ptr<int>(new int(42)), g());
 // }
 //---------------------------------------------------------------------------
-void CheckMemoryLeakNoVar::checkForUnsafeArgAlloc(const Scope *scope)
+void CheckMemoryLeakNoVarImpl::checkForUnsafeArgAlloc(const Scope *scope)
 {
     // This test only applies to C++ source
     if (!mTokenizer->isCPP())
@@ -1200,17 +1188,17 @@ void CheckMemoryLeakNoVar::checkForUnsafeArgAlloc(const Scope *scope)
     }
 }
 
-void CheckMemoryLeakNoVar::functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall)
+void CheckMemoryLeakNoVarImpl::functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall)
 {
     reportError(loc, Severity::error, "leakNoVarFunctionCall", "Allocation with " + alloc + ", " + functionCall + " doesn't release it.", CWE772, Certainty::normal);
 }
 
-void CheckMemoryLeakNoVar::returnValueNotUsedError(const Token *tok, const std::string &alloc)
+void CheckMemoryLeakNoVarImpl::returnValueNotUsedError(const Token *tok, const std::string &alloc)
 {
     reportError(tok, Severity::error, "leakReturnValNotUsed", "$symbol:" + alloc + "\nReturn value of allocation function '$symbol' is not stored.", CWE771, Certainty::normal);
 }
 
-void CheckMemoryLeakNoVar::unsafeArgAllocError(const Token *tok, const std::string &funcName, const std::string &ptrType, const std::string& objType)
+void CheckMemoryLeakNoVarImpl::unsafeArgAllocError(const Token *tok, const std::string &funcName, const std::string &ptrType, const std::string& objType)
 {
     const std::string factoryFunc = ptrType == "shared_ptr" ? "make_shared" : "make_unique";
     reportError(tok, Severity::warning, "leakUnsafeArgAlloc",
@@ -1222,13 +1210,13 @@ void CheckMemoryLeakNoVar::unsafeArgAllocError(const Token *tok, const std::stri
 
 void CheckMemoryLeakNoVar::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    CheckMemoryLeakNoVar checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckMemoryLeakNoVarImpl checkMemoryLeak(&tokenizer, &tokenizer.getSettings(), errorLogger);
     checkMemoryLeak.check();
 }
 
 void CheckMemoryLeakNoVar::getErrorMessages(ErrorLogger *e, const Settings *settings) const
 {
-    CheckMemoryLeakNoVar c(nullptr, settings, e);
+    CheckMemoryLeakNoVarImpl c(nullptr, settings, e);
     c.functionCallLeak(nullptr, "funcName", "funcName");
     c.returnValueNotUsedError(nullptr, "funcName");
     c.unsafeArgAllocError(nullptr, "funcName", "shared_ptr", "int");
diff --git a/lib/checkmemoryleak.h b/lib/checkmemoryleak.h
index c9fb2274252..4f5baf6f865 100644
--- a/lib/checkmemoryleak.h
+++ b/lib/checkmemoryleak.h
@@ -33,6 +33,7 @@
  */
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <cstdint>
@@ -52,18 +53,103 @@ enum class Severity : std::uint8_t;
 /// @addtogroup Core
 /// @{
 
-/** @brief Base class for memory leaks checking */
-class CPPCHECKLIB CheckMemoryLeak {
+
+/**
+ * @brief %CheckMemoryLeakInFunction detects when a function variable is allocated but not deallocated properly.
+ *
+ * The checking is done by looking at each function variable separately. By repeating these 4 steps over and over:
+ * -# locate a function variable
+ * -# create a simple token list that describes the usage of the function variable.
+ * -# simplify the token list.
+ * -# finally, check if the simplified token list contain any leaks.
+ */
+
+class CPPCHECKLIB CheckMemoryLeakInFunction : public Check {
+    friend class TestMemleakInFunction;
+
+public:
+    /** @brief This constructor is used when registering this class */
+    CheckMemoryLeakInFunction() : Check("Memory leaks (function variables)") {}
+
+private:
+    void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
+
+    /** Report all possible errors (for the --errorlist) */
+    void getErrorMessages(ErrorLogger *e, const Settings *settings) const override;
+
+    /**
+     * Get class information (--doc)
+     * @return Wiki formatted information about this class
+     */
+    std::string classInfo() const override {
+        return "Is there any allocated memory when a function goes out of scope\n";
+    }
+};
+
+
+/**
+ * @brief %Check class variables, variables that are allocated in the constructor should be deallocated in the destructor
+ */
+
+class CPPCHECKLIB CheckMemoryLeakInClass : public Check {
+    friend class TestMemleakInClass;
+
+public:
+    CheckMemoryLeakInClass() : Check("Memory leaks (class variables)") {}
+
+private:
+    void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
+
+    void getErrorMessages(ErrorLogger *e, const Settings *settings) const override;
+
+    std::string classInfo() const override {
+        return "If the constructor allocate memory then the destructor must deallocate it.\n";
+    }
+};
+
+
+
+/** @brief detect simple memory leaks for struct members */
+
+class CPPCHECKLIB CheckMemoryLeakStructMember : public Check {
+    friend class TestMemleakStructMember;
+
+public:
+    CheckMemoryLeakStructMember() : Check("Memory leaks (struct members)") {}
+
+private:
+    void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
+
+    void getErrorMessages(ErrorLogger * /*errorLogger*/, const Settings * /*settings*/) const override {}
+
+    std::string classInfo() const override {
+        return "Don't forget to deallocate struct members\n";
+    }
+};
+
+
+
+/** @brief detect simple memory leaks (address not taken) */
+
+class CPPCHECKLIB CheckMemoryLeakNoVar : public Check {
+    friend class TestMemleakNoVar;
+
+public:
+    CheckMemoryLeakNoVar() : Check("Memory leaks (address not taken)") {}
+
 private:
-    /** For access to the tokens */
-    const Tokenizer * const mTokenizer_;
+    void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
-    /** ErrorLogger used to report errors */
-    ErrorLogger * const mErrorLogger_;
+    void getErrorMessages(ErrorLogger *e, const Settings *settings) const override;
 
-    /** Enabled standards */
-    const Settings * const mSettings_;
+    std::string classInfo() const override {
+        return "Not taking the address to allocated memory\n";
+    }
+};
 
+/** @brief Base class for memory leaks checking */
+class CPPCHECKLIB CheckMemoryLeakImpl : public CheckImpl {
+private:
     /**
      * Report error. Similar with the function Check::reportError
      * @param tok the token where the error occurs
@@ -85,12 +171,12 @@ class CPPCHECKLIB CheckMemoryLeak {
     void reportErr(const std::list<const Token *> &callstack, Severity severity, const std::string &id, const std::string &msg, const CWE &cwe) const;
 
 public:
-    CheckMemoryLeak() = delete;
-    CheckMemoryLeak(const CheckMemoryLeak &) = delete;
-    CheckMemoryLeak& operator=(const CheckMemoryLeak &) = delete;
+    CheckMemoryLeakImpl() = delete;
+    CheckMemoryLeakImpl(const CheckMemoryLeakImpl &) = delete;
+    CheckMemoryLeakImpl& operator=(const CheckMemoryLeakImpl &) = delete;
 
-    CheckMemoryLeak(const Tokenizer *t, ErrorLogger *e, const Settings *s)
-        : mTokenizer_(t), mErrorLogger_(e), mSettings_(s) {}
+    CheckMemoryLeakImpl(const Tokenizer *t, const Settings *s, ErrorLogger *e)
+        : CheckImpl(t, s, e) {}
 
     /** @brief What type of allocation are used.. the "Many" means that several types of allocation and deallocation are used */
     enum AllocType : std::uint8_t { No, Malloc, New, NewArray, File, Fd, Pipe, OtherMem, OtherRes, Many };
@@ -165,43 +251,16 @@ class CPPCHECKLIB CheckMemoryLeak {
  * -# finally, check if the simplified token list contain any leaks.
  */
 
-class CPPCHECKLIB CheckMemoryLeakInFunction : public Check, public CheckMemoryLeak {
-    friend class TestMemleakInFunction;
-
+class CPPCHECKLIB CheckMemoryLeakInFunctionImpl : public CheckMemoryLeakImpl {
 public:
-    /** @brief This constructor is used when registering this class */
-    CheckMemoryLeakInFunction() : Check(myName()), CheckMemoryLeak(nullptr, nullptr, nullptr) {}
-
-private:
     /** @brief This constructor is used when running checks */
-    CheckMemoryLeakInFunction(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger), CheckMemoryLeak(tokenizer, errorLogger, settings) {}
-
-    void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
+    CheckMemoryLeakInFunctionImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckMemoryLeakImpl(tokenizer, settings, errorLogger) {}
 
     /**
      * Checking for a memory leak caused by improper realloc usage.
      */
     void checkReallocUsage();
-
-    /** Report all possible errors (for the --errorlist) */
-    void getErrorMessages(ErrorLogger *e, const Settings *settings) const override;
-
-    /**
-     * Get name of class (--doc)
-     * @return name of class
-     */
-    static std::string myName() {
-        return "Memory leaks (function variables)";
-    }
-
-    /**
-     * Get class information (--doc)
-     * @return Wiki formatted information about this class
-     */
-    std::string classInfo() const override {
-        return "Is there any allocated memory when a function goes out of scope\n";
-    }
 };
 
 
@@ -210,17 +269,10 @@ class CPPCHECKLIB CheckMemoryLeakInFunction : public Check, public CheckMemoryLe
  * @brief %Check class variables, variables that are allocated in the constructor should be deallocated in the destructor
  */
 
-class CPPCHECKLIB CheckMemoryLeakInClass : public Check, private CheckMemoryLeak {
-    friend class TestMemleakInClass;
-
+class CPPCHECKLIB CheckMemoryLeakInClassImpl : private CheckMemoryLeakImpl {
 public:
-    CheckMemoryLeakInClass() : Check(myName()), CheckMemoryLeak(nullptr, nullptr, nullptr) {}
-
-private:
-    CheckMemoryLeakInClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger), CheckMemoryLeak(tokenizer, errorLogger, settings) {}
-
-    void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
+    CheckMemoryLeakInClassImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckMemoryLeakImpl(tokenizer, settings, errorLogger) {}
 
     void check();
 
@@ -231,33 +283,17 @@ class CPPCHECKLIB CheckMemoryLeakInClass : public Check, private CheckMemoryLeak
     void publicAllocationError(const Token *tok, const std::string &varname);
 
     void unsafeClassError(const Token *tok, const std::string &classname, const std::string &varname);
-
-    void getErrorMessages(ErrorLogger *e, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "Memory leaks (class variables)";
-    }
-
-    std::string classInfo() const override {
-        return "If the constructor allocate memory then the destructor must deallocate it.\n";
-    }
 };
 
 
 
 /** @brief detect simple memory leaks for struct members */
 
-class CPPCHECKLIB CheckMemoryLeakStructMember : public Check, private CheckMemoryLeak {
-    friend class TestMemleakStructMember;
-
+class CPPCHECKLIB CheckMemoryLeakStructMemberImpl : private CheckMemoryLeakImpl {
 public:
-    CheckMemoryLeakStructMember() : Check(myName()), CheckMemoryLeak(nullptr, nullptr, nullptr) {}
 
-private:
-    CheckMemoryLeakStructMember(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger), CheckMemoryLeak(tokenizer, errorLogger, settings) {}
-
-    void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
+    CheckMemoryLeakStructMemberImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckMemoryLeakImpl(tokenizer, settings, errorLogger) {}
 
     void check();
 
@@ -265,33 +301,16 @@ class CPPCHECKLIB CheckMemoryLeakStructMember : public Check, private CheckMemor
     bool isMalloc(const Variable *variable) const;
 
     void checkStructVariable(const Variable*  variable) const;
-
-    void getErrorMessages(ErrorLogger* /*errorLogger*/, const Settings* /*settings*/) const override;
-
-    static std::string myName() {
-        return "Memory leaks (struct members)";
-    }
-
-    std::string classInfo() const override {
-        return "Don't forget to deallocate struct members\n";
-    }
 };
 
 
 
 /** @brief detect simple memory leaks (address not taken) */
 
-class CPPCHECKLIB CheckMemoryLeakNoVar : public Check, private CheckMemoryLeak {
-    friend class TestMemleakNoVar;
-
+class CPPCHECKLIB CheckMemoryLeakNoVarImpl : private CheckMemoryLeakImpl {
 public:
-    CheckMemoryLeakNoVar() : Check(myName()), CheckMemoryLeak(nullptr, nullptr, nullptr) {}
-
-private:
-    CheckMemoryLeakNoVar(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger), CheckMemoryLeak(tokenizer, errorLogger, settings) {}
-
-    void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
+    CheckMemoryLeakNoVarImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckMemoryLeakImpl(tokenizer, settings, errorLogger) {}
 
     void check();
 
@@ -317,16 +336,6 @@ class CPPCHECKLIB CheckMemoryLeakNoVar : public Check, private CheckMemoryLeak {
     void functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall);
     void returnValueNotUsedError(const Token* tok, const std::string &alloc);
     void unsafeArgAllocError(const Token *tok, const std::string &funcName, const std::string &ptrType, const std::string &objType);
-
-    void getErrorMessages(ErrorLogger *e, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "Memory leaks (address not taken)";
-    }
-
-    std::string classInfo() const override {
-        return "Not taking the address to allocated memory\n";
-    }
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp
index 5bd602488b4..21360e62783 100644
--- a/lib/checknullpointer.cpp
+++ b/lib/checknullpointer.cpp
@@ -54,7 +54,7 @@ static bool checkNullpointerFunctionCallPlausibility(const Function* func, unsig
     return !func || (func->argCount() >= arg && func->getArgumentVar(arg - 1) && func->getArgumentVar(arg - 1)->isPointer());
 }
 
-std::list<const Token*> CheckNullPointer::parseFunctionCall(const Token &tok, const Library &library, bool checkNullArg)
+std::list<const Token*> CheckNullPointerImpl::parseFunctionCall(const Token &tok, const Library &library, bool checkNullArg)
 {
     if (Token::Match(&tok, "%name% ( )") || !tok.tokAt(2))
         return {};
@@ -128,20 +128,6 @@ namespace {
     };
 }
 
-/**
- * Is there a pointer dereference? Everything that should result in
- * a nullpointer dereference error message will result in a true
- * return value. If it's unknown if the pointer is dereferenced false
- * is returned.
- * @param tok token for the pointer
- * @param unknown it is not known if there is a pointer dereference (could be reported as a debug message)
- * @return true => there is a dereference
- */
-bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown) const
-{
-    return isPointerDeRef(tok, unknown, *mSettings);
-}
-
 bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Settings &settings, bool checkNullArg)
 {
     unknown = false;
@@ -155,7 +141,7 @@ bool CheckNullPointer::isPointerDeRef(const Token *tok, bool &unknown, const Set
             ftok = ftok->previous();
         }
         if (ftok && ftok->previous()) {
-            const std::list<const Token *> varlist = parseFunctionCall(*ftok->previous(), settings.library, checkNullArg);
+            const std::list<const Token *> varlist = CheckNullPointerImpl::parseFunctionCall(*ftok->previous(), settings.library, checkNullArg);
             if (std::find(varlist.cbegin(), varlist.cend(), tok) != varlist.cend()) {
                 return true;
             }
@@ -273,7 +259,7 @@ static bool isNullablePointer(const Token* tok)
     return false;
 }
 
-void CheckNullPointer::nullPointerByDeRefAndCheck()
+void CheckNullPointerImpl::nullPointerByDeRefAndCheck()
 {
     const bool printInconclusive = (mSettings->certainty.isEnabled(Certainty::inconclusive));
 
@@ -307,7 +293,7 @@ void CheckNullPointer::nullPointerByDeRefAndCheck()
 
             // Pointer dereference.
             bool unknown = false;
-            if (!isPointerDeRef(tok, unknown)) {
+            if (!CheckNullPointer::isPointerDeRef(tok, unknown, *mSettings)) {
                 if (unknown)
                     nullPointerError(tok, tok->expressionString(), value, true);
                 continue;
@@ -318,7 +304,7 @@ void CheckNullPointer::nullPointerByDeRefAndCheck()
     }
 }
 
-void CheckNullPointer::nullPointer()
+void CheckNullPointerImpl::nullPointer()
 {
     logChecker("CheckNullPointer::nullPointer");
     nullPointerByDeRefAndCheck();
@@ -332,7 +318,7 @@ namespace {
 }
 
 /** Dereferencing null constant (simplified token list) */
-void CheckNullPointer::nullConstantDereference()
+void CheckNullPointerImpl::nullConstantDereference()
 {
     logChecker("CheckNullPointer::nullConstantDereference");
 
@@ -425,14 +411,14 @@ void CheckNullPointer::nullConstantDereference()
     }
 }
 
-void CheckNullPointer::nullPointerError(const Token *tok)
+void CheckNullPointerImpl::nullPointerError(const Token *tok)
 {
     ValueFlow::Value v(0);
     v.setKnown();
     nullPointerError(tok, "", &v, false);
 }
 
-void CheckNullPointer::nullPointerError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive)
+void CheckNullPointerImpl::nullPointerError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive)
 {
     const std::string errmsgcond("$symbol:" + varname + '\n' + ValueFlow::eitherTheConditionIsRedundant(value ? value->condition : nullptr) + " or there is possible null pointer dereference: $symbol.");
     const std::string errmsgdefarg("$symbol:" + varname + "\nPossible null pointer dereference if the default parameter value is used: $symbol");
@@ -486,7 +472,7 @@ void CheckNullPointer::nullPointerError(const Token *tok, const std::string &var
     }
 }
 
-void CheckNullPointer::arithmetic()
+void CheckNullPointerImpl::arithmetic()
 {
     logChecker("CheckNullPointer::arithmetic");
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -533,7 +519,7 @@ static std::string arithmeticTypeString(const Token *tok)
     return "arithmetic";
 }
 
-void CheckNullPointer::pointerArithmeticError(const Token* tok, const ValueFlow::Value *value, bool inconclusive)
+void CheckNullPointerImpl::pointerArithmeticError(const Token* tok, const ValueFlow::Value *value, bool inconclusive)
 {
     // cppcheck-suppress shadowFunction - TODO: fix this
     std::string arithmetic = arithmeticTypeString(tok);
@@ -563,7 +549,7 @@ void CheckNullPointer::pointerArithmeticError(const Token* tok, const ValueFlow:
                 inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckNullPointer::redundantConditionWarning(const Token* tok, const ValueFlow::Value *value, const Token *condition, bool inconclusive)
+void CheckNullPointerImpl::redundantConditionWarning(const Token* tok, const ValueFlow::Value *value, const Token *condition, bool inconclusive)
 {
     // cppcheck-suppress shadowFunction - TODO: fix this
     std::string arithmetic = arithmeticTypeString(tok);
@@ -615,7 +601,7 @@ namespace
 
 Check::FileInfo *CheckNullPointer::getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& /*currentConfig*/) const
 {
-    const std::list<CTU::FileInfo::UnsafeUsage> &unsafeUsage = CTU::getUnsafeUsage(tokenizer, settings, isUnsafeUsage);
+    const std::list<CTU::FileInfo::UnsafeUsage> &unsafeUsage = CTU::getUnsafeUsage(tokenizer, settings, ::isUnsafeUsage);
     if (unsafeUsage.empty())
         return nullptr;
 
@@ -639,9 +625,9 @@ bool CheckNullPointer::analyseWholeProgram(const CTU::FileInfo &ctu, const std::
 {
     (void)settings;
 
-    CheckNullPointer dummy(nullptr, &settings, &errorLogger);
+    CheckNullPointerImpl dummy(nullptr, &settings, &errorLogger);
     dummy.
-    logChecker("CheckNullPointer::analyseWholeProgram"); // unusedfunctions
+    logChecker("CheckNullPointer::analyseWholeProgram");
 
     if (fileInfo.empty())
         return false;
@@ -701,7 +687,7 @@ bool CheckNullPointer::analyseWholeProgram(const CTU::FileInfo &ctu, const std::
 
 void CheckNullPointer::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    CheckNullPointer checkNullPointer(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckNullPointerImpl checkNullPointer(&tokenizer, &tokenizer.getSettings(), errorLogger);
     checkNullPointer.nullPointer();
     checkNullPointer.arithmetic();
     checkNullPointer.nullConstantDereference();
@@ -709,7 +695,7 @@ void CheckNullPointer::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorL
 
 void CheckNullPointer::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckNullPointer c(nullptr, settings, errorLogger);
+    CheckNullPointerImpl c(nullptr, settings, errorLogger);
     c.nullPointerError(nullptr, "pointer", nullptr, false);
     c.pointerArithmeticError(nullptr, nullptr, false);
     // TODO: nullPointerArithmeticOutOfMemory
diff --git a/lib/checknullpointer.h b/lib/checknullpointer.h
index c02feae303e..dc9f60f141e 100644
--- a/lib/checknullpointer.h
+++ b/lib/checknullpointer.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <list>
@@ -51,7 +52,7 @@ class CPPCHECKLIB CheckNullPointer : public Check {
 
 public:
     /** @brief This constructor is used when registering the CheckNullPointer */
-    CheckNullPointer() : Check(myName()) {}
+    CheckNullPointer() : Check("Null pointer") {}
 
     /**
      * Is there a pointer dereference? Everything that should result in
@@ -62,38 +63,14 @@ class CPPCHECKLIB CheckNullPointer : public Check {
      * @param unknown it is not known if there is a pointer dereference (could be reported as a debug message)
      * @return true => there is a dereference
      */
-    bool isPointerDeRef(const Token *tok, bool &unknown) const;
-
     static bool isPointerDeRef(const Token *tok, bool &unknown, const Settings &settings, bool checkNullArg = true);
 
 private:
-    /**
-     * @brief parse a function call and extract information about variable usage
-     * @param tok first token
-     * @param library --library files data
-     * @param checkNullArg perform isnullargbad check for each argument?
-     * @return list of variables that the function reads / writes.
-     */
-    static std::list<const Token*> parseFunctionCall(const Token &tok, const Library &library, bool checkNullArg = true);
-
-    /** @brief This constructor is used when running checks. */
-    CheckNullPointer(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     /** @brief Run checks against the normal token list */
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
-    /** @brief possible null pointer dereference */
-    void nullPointer();
-
-    /** @brief dereferencing null constant (after Tokenizer::simplifyKnownVariables) */
-    void nullConstantDereference();
-
-    void nullPointerError(const Token *tok);
-    void nullPointerError(const Token *tok, const std::string &varname, const ValueFlow::Value* value, bool inconclusive);
-
     /** @brief Parse current TU and extract file info */
-    Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& /*currentConfig*/) const override;
+    Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& currentConfig) const override;
 
     Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override;
 
@@ -103,17 +80,37 @@ class CPPCHECKLIB CheckNullPointer : public Check {
     /** Get error messages. Used by --errorlist */
     void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
 
-    /** Name of check */
-    static std::string myName() {
-        return "Null pointer";
-    }
-
     /** class info in WIKI format. Used by --doc */
     std::string classInfo() const override {
         return "Null pointers\n"
                "- null pointer dereferencing\n"
                "- undefined null pointer arithmetic\n";
     }
+};
+
+class CPPCHECKLIB CheckNullPointerImpl : public CheckImpl {
+public:
+    /** @brief This constructor is used when running checks. */
+    CheckNullPointerImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
+    /**
+     * @brief parse a function call and extract information about variable usage
+     * @param tok first token
+     * @param library --library files data
+     * @param checkNullArg perform isnullargbad check for each argument?
+     * @return list of variables that the function reads / writes.
+     */
+    static std::list<const Token*> parseFunctionCall(const Token &tok, const Library &library, bool checkNullArg = true);
+
+    /** @brief possible null pointer dereference */
+    void nullPointer();
+
+    /** @brief dereferencing null constant (after Tokenizer::simplifyKnownVariables) */
+    void nullConstantDereference();
+
+    void nullPointerError(const Token *tok);
+    void nullPointerError(const Token *tok, const std::string &varname, const ValueFlow::Value* value, bool inconclusive);
 
     /**
      * @brief Does one part of the check for nullPointer().
diff --git a/lib/checkother.cpp b/lib/checkother.cpp
index b454c4410cf..954936ba157 100644
--- a/lib/checkother.cpp
+++ b/lib/checkother.cpp
@@ -80,12 +80,12 @@ static const CWE CWE783(783U);   // Operator Precedence Logic Error
 // - http://www.cplusplus.com/reference/cstdio/getchar/
 // - http://www.cplusplus.com/reference/cstdio/ungetc/ ...
 //----------------------------------------------------------------------------------
-void CheckOther::checkCastIntToCharAndBack()
+void CheckOtherImpl::checkCastIntToCharAndBack()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
 
-    logChecker("CheckOther::checkCastIntToCharAndBack"); // warning
+    logChecker("CheckOtherImpl::checkCastIntToCharAndBack"); // warning
 
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope * scope : symbolDatabase->functionScopes) {
@@ -130,7 +130,7 @@ void CheckOther::checkCastIntToCharAndBack()
     }
 }
 
-void CheckOther::checkCastIntToCharAndBackError(const Token *tok, const std::string &strFunctionName)
+void CheckOtherImpl::checkCastIntToCharAndBackError(const Token *tok, const std::string &strFunctionName)
 {
     reportError(
         tok,
@@ -150,12 +150,12 @@ void CheckOther::checkCastIntToCharAndBackError(const Token *tok, const std::str
 //---------------------------------------------------------------------------
 // Clarify calculation precedence for ternary operators.
 //---------------------------------------------------------------------------
-void CheckOther::clarifyCalculation()
+void CheckOtherImpl::clarifyCalculation()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("clarifyCalculation"))
         return;
 
-    logChecker("CheckOther::clarifyCalculation"); // style
+    logChecker("CheckOtherImpl::clarifyCalculation"); // style
 
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope * scope : symbolDatabase->functionScopes) {
@@ -199,7 +199,7 @@ void CheckOther::clarifyCalculation()
     }
 }
 
-void CheckOther::clarifyCalculationError(const Token *tok, const std::string &op)
+void CheckOtherImpl::clarifyCalculationError(const Token *tok, const std::string &op)
 {
     // suspicious calculation
     const std::string calc("'a" + op + "b?c:d'");
@@ -221,12 +221,12 @@ void CheckOther::clarifyCalculationError(const Token *tok, const std::string &op
 //---------------------------------------------------------------------------
 // Clarify (meaningless) statements like *foo++; with parentheses.
 //---------------------------------------------------------------------------
-void CheckOther::clarifyStatement()
+void CheckOtherImpl::clarifyStatement()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
 
-    logChecker("CheckOther::clarifyStatement"); // warning
+    logChecker("CheckOtherImpl::clarifyStatement"); // warning
 
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope * scope : symbolDatabase->functionScopes) {
@@ -247,7 +247,7 @@ void CheckOther::clarifyStatement()
     }
 }
 
-void CheckOther::clarifyStatementError(const Token *tok)
+void CheckOtherImpl::clarifyStatementError(const Token *tok)
 {
     reportError(tok, Severity::warning, "clarifyStatement", "In expression like '*A++' the result of '*' is unused. Did you intend to write '(*A)++;'?\n"
                 "A statement like '*A++;' might not do what you intended. Postfix 'operator++' is executed before 'operator*'. "
@@ -257,14 +257,14 @@ void CheckOther::clarifyStatementError(const Token *tok)
 //---------------------------------------------------------------------------
 // Check for suspicious occurrences of 'if(); {}'.
 //---------------------------------------------------------------------------
-void CheckOther::checkSuspiciousSemicolon()
+void CheckOtherImpl::checkSuspiciousSemicolon()
 {
     if (!mSettings->certainty.isEnabled(Certainty::inconclusive) || !mSettings->severity.isEnabled(Severity::warning))
         return;
 
     const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
 
-    logChecker("CheckOther::checkSuspiciousSemicolon"); // warning,inconclusive
+    logChecker("CheckOtherImpl::checkSuspiciousSemicolon"); // warning,inconclusive
 
     // Look for "if(); {}", "for(); {}" or "while(); {}"
     for (const Scope &scope : symbolDatabase->scopeList) {
@@ -281,7 +281,7 @@ void CheckOther::checkSuspiciousSemicolon()
     }
 }
 
-void CheckOther::suspiciousSemicolonError(const Token* tok)
+void CheckOtherImpl::suspiciousSemicolonError(const Token* tok)
 {
     reportError(tok, Severity::warning, "suspiciousSemicolon",
                 "Suspicious use of ; at the end of '" + (tok ? tok->str() : std::string()) + "' statement.", CWE398, Certainty::normal);
@@ -329,7 +329,7 @@ static bool isDangerousTypeConversion(const Token* const tok)
 //---------------------------------------------------------------------------
 // For C++ code, warn if C-style casts are used on pointer types
 //---------------------------------------------------------------------------
-void CheckOther::warningOldStylePointerCast()
+void CheckOtherImpl::warningOldStylePointerCast()
 {
     // Only valid on C++ code
     if (!mTokenizer->isCPP())
@@ -338,7 +338,7 @@ void CheckOther::warningOldStylePointerCast()
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("cstyleCast"))
         return;
 
-    logChecker("CheckOther::warningOldStylePointerCast"); // style,c++
+    logChecker("CheckOtherImpl::warningOldStylePointerCast"); // style,c++
 
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope * scope : symbolDatabase->functionScopes) {
@@ -394,7 +394,7 @@ void CheckOther::warningOldStylePointerCast()
     }
 }
 
-void CheckOther::cstyleCastError(const Token *tok, bool isPtr)
+void CheckOtherImpl::cstyleCastError(const Token *tok, bool isPtr)
 {
     const std::string type = isPtr ? "pointer" : "reference";
     reportError(tok, Severity::style, "cstyleCast",
@@ -405,7 +405,7 @@ void CheckOther::cstyleCastError(const Token *tok, bool isPtr)
                 "which kind of cast is expected.", CWE398, Certainty::normal);
 }
 
-void CheckOther::warningDangerousTypeCast()
+void CheckOtherImpl::warningDangerousTypeCast()
 {
     // Only valid on C++ code
     if (!mTokenizer->isCPP())
@@ -433,7 +433,7 @@ void CheckOther::warningDangerousTypeCast()
     }
 }
 
-void CheckOther::dangerousTypeCastError(const Token *tok, bool isPtr)
+void CheckOtherImpl::dangerousTypeCastError(const Token *tok, bool isPtr)
 {
     //const std::string type = isPtr ? "pointer" : "reference";
     (void)isPtr;
@@ -442,7 +442,7 @@ void CheckOther::dangerousTypeCastError(const Token *tok, bool isPtr)
                 CWE398, Certainty::normal);
 }
 
-void CheckOther::warningIntToPointerCast()
+void CheckOtherImpl::warningIntToPointerCast()
 {
     if (!mSettings->severity.isEnabled(Severity::portability) && !mSettings->isPremiumEnabled("cstyleCast"))
         return;
@@ -471,14 +471,14 @@ void CheckOther::warningIntToPointerCast()
     }
 }
 
-void CheckOther::intToPointerCastError(const Token *tok, const std::string& format)
+void CheckOtherImpl::intToPointerCastError(const Token *tok, const std::string& format)
 {
     reportError(tok, Severity::portability, "intToPointerCast",
                 "Casting non-zero " + format + " integer literal to pointer.",
                 CWE398, Certainty::normal);
 }
 
-void CheckOther::suspiciousFloatingPointCast()
+void CheckOtherImpl::suspiciousFloatingPointCast()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("suspiciousFloatingPointCast"))
         return;
@@ -528,7 +528,7 @@ void CheckOther::suspiciousFloatingPointCast()
     }
 }
 
-void CheckOther::suspiciousFloatingPointCastError(const Token* tok)
+void CheckOtherImpl::suspiciousFloatingPointCastError(const Token* tok)
 {
     reportError(tok, Severity::style, "suspiciousFloatingPointCast",
                 "Floating-point cast causes loss of precision.\n"
@@ -539,12 +539,12 @@ void CheckOther::suspiciousFloatingPointCastError(const Token* tok)
 // float* f; double* d = (double*)f; <-- Pointer cast to a type with an incompatible binary data representation
 //---------------------------------------------------------------------------
 
-void CheckOther::invalidPointerCast()
+void CheckOtherImpl::invalidPointerCast()
 {
     if (!mSettings->severity.isEnabled(Severity::portability))
         return;
 
-    logChecker("CheckOther::invalidPointerCast"); // portability
+    logChecker("CheckOtherImpl::invalidPointerCast"); // portability
 
     const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
     const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -579,7 +579,7 @@ void CheckOther::invalidPointerCast()
 }
 
 
-void CheckOther::invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive, bool toIsInt)
+void CheckOtherImpl::invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive, bool toIsInt)
 {
     if (toIsInt) { // If we cast something to int*, this can be useful to play with its binary data representation
         reportError(tok, Severity::portability, "invalidPointerCast", "Casting from " + from + " to " + to + " is not portable due to different binary data representations on different platforms.", CWE704, inconclusive ? Certainty::inconclusive : Certainty::normal);
@@ -592,14 +592,14 @@ void CheckOther::invalidPointerCastError(const Token* tok, const std::string& fr
 // Detect redundant assignments: x = 0; x = 4;
 //---------------------------------------------------------------------------
 
-void CheckOther::checkRedundantAssignment()
+void CheckOtherImpl::checkRedundantAssignment()
 {
     if (!mSettings->severity.isEnabled(Severity::style) &&
         !mSettings->isPremiumEnabled("redundantAssignment") &&
         !mSettings->isPremiumEnabled("redundantAssignInSwitch"))
         return;
 
-    logChecker("CheckOther::checkRedundantAssignment"); // style
+    logChecker("CheckOtherImpl::checkRedundantAssignment"); // style
 
     const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope *scope : symbolDatabase->functionScopes) {
@@ -729,7 +729,7 @@ void CheckOther::checkRedundantAssignment()
     }
 }
 
-void CheckOther::redundantCopyError(const Token *tok1, const Token* tok2, const std::string& var)
+void CheckOtherImpl::redundantCopyError(const Token *tok1, const Token* tok2, const std::string& var)
 {
     const std::list<const Token *> callstack = { tok1, tok2 };
     reportError(callstack, Severity::performance, "redundantCopy",
@@ -737,7 +737,7 @@ void CheckOther::redundantCopyError(const Token *tok1, const Token* tok2, const
                 "Buffer '$symbol' is being written before its old content has been used.", CWE563, Certainty::normal);
 }
 
-void CheckOther::redundantAssignmentError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive)
+void CheckOtherImpl::redundantAssignmentError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive)
 {
     ErrorPath errorPath = { ErrorPathItem(tok1, var + " is assigned"), ErrorPathItem(tok2, var + " is overwritten") };
     if (inconclusive)
@@ -751,7 +751,7 @@ void CheckOther::redundantAssignmentError(const Token *tok1, const Token* tok2,
                     "Variable '$symbol' is reassigned a value before the old one has been used.", CWE563, Certainty::normal);
 }
 
-void CheckOther::redundantInitializationError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive)
+void CheckOtherImpl::redundantInitializationError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive)
 {
     ErrorPath errorPath = { ErrorPathItem(tok1, var + " is initialized"), ErrorPathItem(tok2, var + " is overwritten") };
     reportError(std::move(errorPath), Severity::style, "redundantInitialization",
@@ -760,7 +760,7 @@ void CheckOther::redundantInitializationError(const Token *tok1, const Token* to
                 inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckOther::redundantAssignmentInSwitchError(const Token *tok1, const Token* tok2, const std::string &var)
+void CheckOtherImpl::redundantAssignmentInSwitchError(const Token *tok1, const Token* tok2, const std::string &var)
 {
     ErrorPath errorPath = { ErrorPathItem(tok1, "$symbol is assigned"), ErrorPathItem(tok2, "$symbol is overwritten") };
     reportError(std::move(errorPath), Severity::style, "redundantAssignInSwitch",
@@ -768,7 +768,7 @@ void CheckOther::redundantAssignmentInSwitchError(const Token *tok1, const Token
                 "Variable '$symbol' is reassigned a value before the old one has been used. 'break;' missing?", CWE563, Certainty::normal);
 }
 
-void CheckOther::redundantAssignmentSameValueError(const Token *tok, const ValueFlow::Value* val, const std::string &var)
+void CheckOtherImpl::redundantAssignmentSameValueError(const Token *tok, const ValueFlow::Value* val, const std::string &var)
 {
     auto errorPath = val->errorPath;
     errorPath.emplace_back(tok, "");
@@ -792,12 +792,12 @@ static inline bool isFunctionOrBreakPattern(const Token *tok)
     return Token::Match(tok, "%name% (") || Token::Match(tok, "break|continue|return|exit|goto|throw");
 }
 
-void CheckOther::redundantBitwiseOperationInSwitchError()
+void CheckOtherImpl::redundantBitwiseOperationInSwitchError()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
 
-    logChecker("CheckOther::redundantBitwiseOperationInSwitch"); // warning
+    logChecker("CheckOtherImpl::redundantBitwiseOperationInSwitch"); // warning
 
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
 
@@ -909,7 +909,7 @@ void CheckOther::redundantBitwiseOperationInSwitchError()
     }
 }
 
-void CheckOther::redundantBitwiseOperationInSwitchError(const Token *tok, const std::string &varname)
+void CheckOtherImpl::redundantBitwiseOperationInSwitchError(const Token *tok, const std::string &varname)
 {
     reportError(tok, Severity::style,
                 "redundantBitwiseOperationInSwitch",
@@ -921,12 +921,12 @@ void CheckOther::redundantBitwiseOperationInSwitchError(const Token *tok, const
 //---------------------------------------------------------------------------
 // Check for statements like case A||B: in switch()
 //---------------------------------------------------------------------------
-void CheckOther::checkSuspiciousCaseInSwitch()
+void CheckOtherImpl::checkSuspiciousCaseInSwitch()
 {
     if (!mSettings->certainty.isEnabled(Certainty::inconclusive) || !mSettings->severity.isEnabled(Severity::warning))
         return;
 
-    logChecker("CheckOther::checkSuspiciousCaseInSwitch"); // warning,inconclusive
+    logChecker("CheckOtherImpl::checkSuspiciousCaseInSwitch"); // warning,inconclusive
 
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
 
@@ -955,7 +955,7 @@ void CheckOther::checkSuspiciousCaseInSwitch()
     }
 }
 
-void CheckOther::suspiciousCaseInSwitchError(const Token* tok, const std::string& operatorString)
+void CheckOtherImpl::suspiciousCaseInSwitchError(const Token* tok, const std::string& operatorString)
 {
     reportError(tok, Severity::warning, "suspiciousCase",
                 "Found suspicious case label in switch(). Operator '" + operatorString + "' probably doesn't work as intended.\n"
@@ -1005,7 +1005,7 @@ static bool isVardeclInSwitch(const Token* tok)
 //    Detect dead code, that follows such a statement. e.g.:
 //        return(0); foo();
 //---------------------------------------------------------------------------
-void CheckOther::checkUnreachableCode()
+void CheckOtherImpl::checkUnreachableCode()
 {
     // misra-c-2012-2.1
     // misra-c-2023-2.1
@@ -1014,7 +1014,7 @@ void CheckOther::checkUnreachableCode()
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("duplicateBreak") && !mSettings->isPremiumEnabled("unreachableCode"))
         return;
 
-    logChecker("CheckOther::checkUnreachableCode"); // style
+    logChecker("CheckOtherImpl::checkUnreachableCode"); // style
 
     const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
     const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -1125,7 +1125,7 @@ void CheckOther::checkUnreachableCode()
     }
 }
 
-void CheckOther::duplicateBreakError(const Token *tok, bool inconclusive)
+void CheckOtherImpl::duplicateBreakError(const Token *tok, bool inconclusive)
 {
     reportError(tok, Severity::style, "duplicateBreak",
                 "Consecutive return, break, continue, goto or throw statements are unnecessary.\n"
@@ -1133,7 +1133,7 @@ void CheckOther::duplicateBreakError(const Token *tok, bool inconclusive)
                 "The second statement can never be executed, and so should be removed.", CWE561, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckOther::unreachableCodeError(const Token *tok, const Token* noreturn, bool inconclusive)
+void CheckOtherImpl::unreachableCodeError(const Token *tok, const Token* noreturn, bool inconclusive)
 {
     std::string msg = "Statements following ";
     if (noreturn && (noreturn->function() || mSettings->library.isnoreturn(noreturn)))
@@ -1147,7 +1147,7 @@ void CheckOther::unreachableCodeError(const Token *tok, const Token* noreturn, b
                 msg, CWE561, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckOther::redundantContinueError(const Token *tok)
+void CheckOtherImpl::redundantContinueError(const Token *tok)
 {
     reportError(tok, Severity::style, "redundantContinue",
                 "'continue' is redundant since it is the last statement in a loop.", CWE561, Certainty::normal);
@@ -1183,7 +1183,7 @@ static bool isSimpleExpr(const Token* tok, const Variable* var, const Settings&
 //---------------------------------------------------------------------------
 // Check scope of variables..
 //---------------------------------------------------------------------------
-void CheckOther::checkVariableScope()
+void CheckOtherImpl::checkVariableScope()
 {
     if (mSettings->clang)
         return;
@@ -1198,7 +1198,7 @@ void CheckOther::checkVariableScope()
     if (mSettings->daca && mTokenizer->isC())
         return;
 
-    logChecker("CheckOther::checkVariableScope"); // style,notclang
+    logChecker("CheckOtherImpl::checkVariableScope"); // style,notclang
 
     for (const Variable* var : symbolDatabase->variableList()) {
         if (!var || !var->isLocal() || var->isConst())
@@ -1335,7 +1335,7 @@ static bool isOnlyUsedInCurrentScope(const Variable* var, const Token *tok, cons
     return !Token::findmatch(tok->scope()->bodyEnd, "%varid%", var->scope()->bodyEnd, var->declarationId());
 }
 
-bool CheckOther::checkInnerScope(const Token *tok, const Variable* var, bool& used) const
+bool CheckOtherImpl::checkInnerScope(const Token *tok, const Variable* var, bool& used) const
 {
     const Scope* scope = tok->next()->scope();
     bool loopVariable = scope->isLoopScope();
@@ -1446,7 +1446,7 @@ bool CheckOther::checkInnerScope(const Token *tok, const Variable* var, bool& us
     return true;
 }
 
-void CheckOther::variableScopeError(const Token *tok, const std::string &varname)
+void CheckOtherImpl::variableScopeError(const Token *tok, const std::string &varname)
 {
     reportError(tok,
                 Severity::style,
@@ -1473,7 +1473,7 @@ void CheckOther::variableScopeError(const Token *tok, const std::string &varname
 //---------------------------------------------------------------------------
 // Comma in return statement: return a+1, b++;. (experimental)
 //---------------------------------------------------------------------------
-void CheckOther::checkCommaSeparatedReturn()
+void CheckOtherImpl::checkCommaSeparatedReturn()
 {
     // TODO: This is experimental for now. See #5076
     if ((true) || !mSettings->severity.isEnabled(Severity::style)) // NOLINT(readability-simplify-boolean-expr,readability-redundant-parentheses)
@@ -1500,7 +1500,7 @@ void CheckOther::checkCommaSeparatedReturn()
     }
 }
 
-void CheckOther::commaSeparatedReturnError(const Token *tok)
+void CheckOtherImpl::commaSeparatedReturnError(const Token *tok)
 {
     reportError(tok,
                 Severity::style,
@@ -1538,12 +1538,12 @@ static bool isLargeContainer(const Variable* var, const Settings& settings)
     return arraySize > maxByValueSize;
 }
 
-void CheckOther::checkPassByReference()
+void CheckOtherImpl::checkPassByReference()
 {
     if (!mSettings->severity.isEnabled(Severity::performance) || mTokenizer->isC())
         return;
 
-    logChecker("CheckOther::checkPassByReference"); // performance,c++
+    logChecker("CheckOtherImpl::checkPassByReference"); // performance,c++
 
     const SymbolDatabase * const symbolDatabase = mTokenizer->getSymbolDatabase();
 
@@ -1617,7 +1617,7 @@ void CheckOther::checkPassByReference()
     }
 }
 
-void CheckOther::passedByValueError(const Variable* var, bool inconclusive, bool isRangeBasedFor)
+void CheckOtherImpl::passedByValueError(const Variable* var, bool inconclusive, bool isRangeBasedFor)
 {
     std::string id = isRangeBasedFor ? "iterateByValue" : "passedByValue";
     const std::string action = isRangeBasedFor ? "declared as": "passed by";
@@ -1682,7 +1682,7 @@ static bool isCastToVoid(const Variable* var)
     return false;
 }
 
-void CheckOther::checkConstVariable()
+void CheckOtherImpl::checkConstVariable()
 {
     if ((!mSettings->severity.isEnabled(Severity::style) || mTokenizer->isC()) && !mSettings->isPremiumEnabled("constVariable"))
         return;
@@ -1875,7 +1875,7 @@ static const Function* getEnclosingFunction(const Variable* var)
     return scope ? scope->function : nullptr;
 }
 
-void CheckOther::checkConstPointer()
+void CheckOtherImpl::checkConstPointer()
 {
     if (!mSettings->severity.isEnabled(Severity::style) &&
         !mSettings->isPremiumEnabled("constParameter") &&
@@ -1884,7 +1884,7 @@ void CheckOther::checkConstPointer()
         !mSettings->isPremiumEnabled("constVariablePointer"))
         return;
 
-    logChecker("CheckOther::checkConstPointer"); // style
+    logChecker("CheckOtherImpl::checkConstPointer"); // style
 
     std::set<const Variable*, CompareVariables> pointers, nonConstPointers;
     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
@@ -2051,7 +2051,7 @@ void CheckOther::checkConstPointer()
     }
 }
 
-void CheckOther::constVariableError(const Variable *var, const Function *function)
+void CheckOtherImpl::constVariableError(const Variable *var, const Function *function)
 {
     if (!var) {
         reportError(nullptr, Severity::style, "constParameter", "Parameter 'x' can be declared with const");
@@ -2089,14 +2089,14 @@ void CheckOther::constVariableError(const Variable *var, const Function *functio
 // Check usage of char variables..
 //---------------------------------------------------------------------------
 
-void CheckOther::checkCharVariable()
+void CheckOtherImpl::checkCharVariable()
 {
     const bool warning = mSettings->severity.isEnabled(Severity::warning);
     const bool portability = mSettings->severity.isEnabled(Severity::portability);
     if (!warning && !portability)
         return;
 
-    logChecker("CheckOther::checkCharVariable"); // warning,portability
+    logChecker("CheckOtherImpl::checkCharVariable"); // warning,portability
 
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope * scope : symbolDatabase->functionScopes) {
@@ -2140,7 +2140,7 @@ void CheckOther::checkCharVariable()
     }
 }
 
-void CheckOther::signedCharArrayIndexError(const Token *tok)
+void CheckOtherImpl::signedCharArrayIndexError(const Token *tok)
 {
     reportError(tok,
                 Severity::warning,
@@ -2151,7 +2151,7 @@ void CheckOther::signedCharArrayIndexError(const Token *tok)
                 "because of sign extension.", CWE128, Certainty::normal);
 }
 
-void CheckOther::unknownSignCharArrayIndexError(const Token *tok)
+void CheckOtherImpl::unknownSignCharArrayIndexError(const Token *tok)
 {
     reportError(tok,
                 Severity::portability,
@@ -2161,7 +2161,7 @@ void CheckOther::unknownSignCharArrayIndexError(const Token *tok)
                 "treated depending on whether 'char' is signed or unsigned on target platform.", CWE758, Certainty::normal);
 }
 
-void CheckOther::charBitOpError(const Token *tok)
+void CheckOtherImpl::charBitOpError(const Token *tok)
 {
     reportError(tok,
                 Severity::warning,
@@ -2348,13 +2348,13 @@ static bool isConstTop(const Token *tok)
     return false;
 }
 
-void CheckOther::checkIncompleteStatement()
+void CheckOtherImpl::checkIncompleteStatement()
 {
     if (!mSettings->severity.isEnabled(Severity::warning) &&
         !mSettings->isPremiumEnabled("constStatement"))
         return;
 
-    logChecker("CheckOther::checkIncompleteStatement"); // warning
+    logChecker("CheckOtherImpl::checkIncompleteStatement"); // warning
 
     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
         const Scope *scope = tok->scope();
@@ -2410,7 +2410,7 @@ void CheckOther::checkIncompleteStatement()
     }
 }
 
-void CheckOther::constStatementError(const Token *tok, const std::string &type, bool inconclusive)
+void CheckOtherImpl::constStatementError(const Token *tok, const std::string &type, bool inconclusive)
 {
     const Token *valueTok = tok;
     while (valueTok && valueTok->isCast())
@@ -2465,9 +2465,9 @@ void CheckOther::constStatementError(const Token *tok, const std::string &type,
 //---------------------------------------------------------------------------
 // Detect division by zero.
 //---------------------------------------------------------------------------
-void CheckOther::checkZeroDivision()
+void CheckOtherImpl::checkZeroDivision()
 {
-    logChecker("CheckOther::checkZeroDivision");
+    logChecker("CheckOtherImpl::checkZeroDivision");
 
     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
         if (!tok->astOperand2() || !tok->astOperand1())
@@ -2486,7 +2486,7 @@ void CheckOther::checkZeroDivision()
     }
 }
 
-void CheckOther::zerodivError(const Token *tok, const ValueFlow::Value *value)
+void CheckOtherImpl::zerodivError(const Token *tok, const ValueFlow::Value *value)
 {
     if (!tok && !value) {
         reportError(tok, Severity::error, "zerodiv", "Division by zero.", CWE369, Certainty::normal);
@@ -2515,11 +2515,11 @@ void CheckOther::zerodivError(const Token *tok, const ValueFlow::Value *value)
 // double d = 1.0 / 0.0 + 100.0;
 //---------------------------------------------------------------------------
 
-void CheckOther::checkNanInArithmeticExpression()
+void CheckOtherImpl::checkNanInArithmeticExpression()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("nanInArithmeticExpression"))
         return;
-    logChecker("CheckOther::checkNanInArithmeticExpression"); // style
+    logChecker("CheckOtherImpl::checkNanInArithmeticExpression"); // style
     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
         if (tok->str() != "/")
             continue;
@@ -2530,7 +2530,7 @@ void CheckOther::checkNanInArithmeticExpression()
     }
 }
 
-void CheckOther::nanInArithmeticExpressionError(const Token *tok)
+void CheckOtherImpl::nanInArithmeticExpressionError(const Token *tok)
 {
     reportError(tok, Severity::style, "nanInArithmeticExpression",
                 "Using NaN/Inf in a computation.\n"
@@ -2541,7 +2541,7 @@ void CheckOther::nanInArithmeticExpressionError(const Token *tok)
 //---------------------------------------------------------------------------
 // Creating instance of classes which are destroyed immediately
 //---------------------------------------------------------------------------
-void CheckOther::checkMisusedScopedObject()
+void CheckOtherImpl::checkMisusedScopedObject()
 {
     // Skip this check for .c files
     if (mTokenizer->isC())
@@ -2550,7 +2550,7 @@ void CheckOther::checkMisusedScopedObject()
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedScopedObject"))
         return;
 
-    logChecker("CheckOther::checkMisusedScopedObject"); // style,c++
+    logChecker("CheckOtherImpl::checkMisusedScopedObject"); // style,c++
 
     auto getConstructorTok = [](const Token* tok, std::string& typeStr) -> const Token* {
         if (!Token::Match(tok, "[;{}] %name%") || tok->next()->isKeyword())
@@ -2616,7 +2616,7 @@ void CheckOther::checkMisusedScopedObject()
     }
 }
 
-void CheckOther::misusedScopeObjectError(const Token *tok, const std::string& varname, bool isAssignment)
+void CheckOtherImpl::misusedScopeObjectError(const Token *tok, const std::string& varname, bool isAssignment)
 {
     std::string msg = "Instance of '$symbol' object is destroyed immediately";
     msg += isAssignment ? ", assignment has no effect." : ".";
@@ -2641,7 +2641,7 @@ static const Token * getSingleExpressionInBlock(const Token * tok)
 // check for duplicate code in if and else branches
 // if (a) { b = true; } else { b = true; }
 //-----------------------------------------------------------------------------
-void CheckOther::checkDuplicateBranch()
+void CheckOtherImpl::checkDuplicateBranch()
 {
     // This is inconclusive since in practice most warnings are noise:
     // * There can be unfixed low-priority todos. The code is fine as it
@@ -2654,7 +2654,7 @@ void CheckOther::checkDuplicateBranch()
     if (!mSettings->severity.isEnabled(Severity::style) || !mSettings->certainty.isEnabled(Certainty::inconclusive))
         return;
 
-    logChecker("CheckOther::checkDuplicateBranch"); // style,inconclusive
+    logChecker("CheckOtherImpl::checkDuplicateBranch"); // style,inconclusive
 
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
 
@@ -2720,7 +2720,7 @@ void CheckOther::checkDuplicateBranch()
     }
 }
 
-void CheckOther::duplicateBranchError(const Token *tok1, const Token *tok2, ErrorPath errors)
+void CheckOtherImpl::duplicateBranchError(const Token *tok1, const Token *tok2, ErrorPath errors)
 {
     errors.emplace_back(tok2, "");
     errors.emplace_back(tok1, "");
@@ -2737,12 +2737,12 @@ void CheckOther::duplicateBranchError(const Token *tok1, const Token *tok2, Erro
 // char* p = malloc(100);
 // free(p + 10);
 //-----------------------------------------------------------------------------
-void CheckOther::checkInvalidFree()
+void CheckOtherImpl::checkInvalidFree()
 {
     std::map<int, bool> inconclusive;
     std::map<int, std::string> allocation;
 
-    logChecker("CheckOther::checkInvalidFree");
+    logChecker("CheckOtherImpl::checkInvalidFree");
 
     const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
     const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -2811,7 +2811,7 @@ void CheckOther::checkInvalidFree()
     }
 }
 
-void CheckOther::invalidFreeError(const Token *tok, const std::string &allocation, bool inconclusive)
+void CheckOtherImpl::invalidFreeError(const Token *tok, const std::string &allocation, bool inconclusive)
 {
     std::string alloc = allocation;
     if (alloc != "new")
@@ -2870,7 +2870,7 @@ isStaticAssert(const Settings &settings, const Token *tok)
     return false;
 }
 
-void CheckOther::checkDuplicateExpression()
+void CheckOtherImpl::checkDuplicateExpression()
 {
     {
         const bool styleEnabled = mSettings->severity.isEnabled(Severity::style);
@@ -2886,7 +2886,7 @@ void CheckOther::checkDuplicateExpression()
             return;
     }
 
-    logChecker("CheckOther::checkDuplicateExpression"); // style,warning
+    logChecker("CheckOtherImpl::checkDuplicateExpression"); // style,warning
 
     // Parse all executing scopes..
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -3068,7 +3068,7 @@ void CheckOther::checkDuplicateExpression()
     }
 }
 
-void CheckOther::oppositeExpressionError(const Token *opTok, ErrorPath errors)
+void CheckOtherImpl::oppositeExpressionError(const Token *opTok, ErrorPath errors)
 {
     errors.emplace_back(opTok, "");
 
@@ -3080,7 +3080,7 @@ void CheckOther::oppositeExpressionError(const Token *opTok, ErrorPath errors)
                 "determine if it is correct.", CWE398, Certainty::normal);
 }
 
-void CheckOther::duplicateExpressionError(const Token *tok1, const Token *tok2, const Token *opTok, ErrorPath errors, bool hasMultipleExpr)
+void CheckOtherImpl::duplicateExpressionError(const Token *tok1, const Token *tok2, const Token *opTok, ErrorPath errors, bool hasMultipleExpr)
 {
     errors.emplace_back(opTok, "");
 
@@ -3108,7 +3108,7 @@ void CheckOther::duplicateExpressionError(const Token *tok1, const Token *tok2,
                 "determine if it is correct.", CWE398, Certainty::normal);
 }
 
-void CheckOther::duplicateAssignExpressionError(const Token *tok1, const Token *tok2, bool inconclusive)
+void CheckOtherImpl::duplicateAssignExpressionError(const Token *tok1, const Token *tok2, bool inconclusive)
 {
     const std::list<const Token *> toks = { tok2, tok1 };
 
@@ -3122,7 +3122,7 @@ void CheckOther::duplicateAssignExpressionError(const Token *tok1, const Token *
                 "determine if it is correct.", CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckOther::duplicateExpressionTernaryError(const Token *tok, ErrorPath errors)
+void CheckOtherImpl::duplicateExpressionTernaryError(const Token *tok, ErrorPath errors)
 {
     errors.emplace_back(tok, "");
     reportError(std::move(errors), Severity::style, "duplicateExpressionTernary", "Same expression in both branches of ternary operator.\n"
@@ -3130,14 +3130,14 @@ void CheckOther::duplicateExpressionTernaryError(const Token *tok, ErrorPath err
                 "the same code is executed regardless of the condition.", CWE398, Certainty::normal);
 }
 
-void CheckOther::duplicateValueTernaryError(const Token *tok)
+void CheckOtherImpl::duplicateValueTernaryError(const Token *tok)
 {
     reportError(tok, Severity::style, "duplicateValueTernary", "Same value in both branches of ternary operator.\n"
                 "Finding the same value in both branches of ternary operator is suspicious as "
                 "the same code is executed regardless of the condition.", CWE398, Certainty::normal);
 }
 
-void CheckOther::selfAssignmentError(const Token *tok, const std::string &varname)
+void CheckOtherImpl::selfAssignmentError(const Token *tok, const std::string &varname)
 {
     reportError(tok, Severity::style,
                 "selfAssignment",
@@ -3154,12 +3154,12 @@ void CheckOther::selfAssignmentError(const Token *tok, const std::string &varnam
 // Reference:
 // - http://www.cplusplus.com/reference/cmath/
 //-----------------------------------------------------------------------------
-void CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalse()
+void CheckOtherImpl::checkComparisonFunctionIsAlwaysTrueOrFalse()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
 
-    logChecker("CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalse"); // warning
+    logChecker("CheckOtherImpl::checkComparisonFunctionIsAlwaysTrueOrFalse"); // warning
 
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope * scope : symbolDatabase->functionScopes) {
@@ -3184,7 +3184,7 @@ void CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalse()
         }
     }
 }
-void CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &functionName, const std::string &varName, const bool result)
+void CheckOtherImpl::checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &functionName, const std::string &varName, const bool result)
 {
     const std::string strResult = bool_to_string(result);
     const CWE cweResult = result ? CWE571 : CWE570;
@@ -3199,12 +3199,12 @@ void CheckOther::checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* to
 //---------------------------------------------------------------------------
 // Check testing sign of unsigned variables and pointers.
 //---------------------------------------------------------------------------
-void CheckOther::checkSignOfUnsignedVariable()
+void CheckOtherImpl::checkSignOfUnsignedVariable()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unsignedLessThanZero"))
         return;
 
-    logChecker("CheckOther::checkSignOfUnsignedVariable"); // style
+    logChecker("CheckOtherImpl::checkSignOfUnsignedVariable"); // style
 
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
 
@@ -3213,13 +3213,13 @@ void CheckOther::checkSignOfUnsignedVariable()
         for (const Token *tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
             const ValueFlow::Value *zeroValue = nullptr;
             const Token *nonZeroExpr = nullptr;
-            if (comparisonNonZeroExpressionLessThanZero(tok, zeroValue, nonZeroExpr)) {
+            if (CheckOther::comparisonNonZeroExpressionLessThanZero(tok, zeroValue, nonZeroExpr)) {
                 const ValueType* vt = nonZeroExpr->valueType();
                 if (vt->pointer)
                     pointerLessThanZeroError(tok, zeroValue);
                 else
                     unsignedLessThanZeroError(tok, zeroValue, nonZeroExpr->expressionString());
-            } else if (testIfNonZeroExpressionIsPositive(tok, zeroValue, nonZeroExpr)) {
+            } else if (CheckOther::testIfNonZeroExpressionIsPositive(tok, zeroValue, nonZeroExpr)) {
                 const ValueType* vt = nonZeroExpr->valueType();
                 if (vt->pointer)
                     pointerPositiveError(tok, zeroValue);
@@ -3278,7 +3278,7 @@ bool CheckOther::testIfNonZeroExpressionIsPositive(const Token *tok, const Value
     return vt && (vt->pointer || vt->sign == ValueType::UNSIGNED);
 }
 
-void CheckOther::unsignedLessThanZeroError(const Token *tok, const ValueFlow::Value * v, const std::string &varname)
+void CheckOtherImpl::unsignedLessThanZeroError(const Token *tok, const ValueFlow::Value * v, const std::string &varname)
 {
     reportError(getErrorPath(tok, v, "Unsigned less than zero"), Severity::style, "unsignedLessThanZero",
                 "$symbol:" + varname + "\n"
@@ -3287,20 +3287,20 @@ void CheckOther::unsignedLessThanZeroError(const Token *tok, const ValueFlow::Va
                 "is either pointless or an error to check if it is.", CWE570, Certainty::normal);
 }
 
-void CheckOther::pointerLessThanZeroError(const Token *tok, const ValueFlow::Value *v)
+void CheckOtherImpl::pointerLessThanZeroError(const Token *tok, const ValueFlow::Value *v)
 {
     reportError(getErrorPath(tok, v, "Pointer less than zero"), Severity::style, "pointerLessThanZero",
                 "A pointer can not be negative so it is either pointless or an error to check if it is.", CWE570, Certainty::normal);
 }
 
-void CheckOther::unsignedPositiveError(const Token *tok, const ValueFlow::Value * v, const std::string &varname)
+void CheckOtherImpl::unsignedPositiveError(const Token *tok, const ValueFlow::Value * v, const std::string &varname)
 {
     reportError(getErrorPath(tok, v, "Unsigned positive"), Severity::style, "unsignedPositive",
                 "$symbol:" + varname + "\n"
                 "Unsigned expression '$symbol' can't be negative so it is unnecessary to test it.", CWE570, Certainty::normal);
 }
 
-void CheckOther::pointerPositiveError(const Token *tok, const ValueFlow::Value * v)
+void CheckOtherImpl::pointerPositiveError(const Token *tok, const ValueFlow::Value * v)
 {
     reportError(getErrorPath(tok, v, "Pointer positive"), Severity::style, "pointerPositive",
                 "A pointer can not be negative so it is either pointless or an error to check if it is not.", CWE570, Certainty::normal);
@@ -3383,12 +3383,12 @@ static bool checkVariableAssignment(const Token* tok, const ValueType* vtLhs, co
     return scope && scope->function && (!scope->functionOf || scope->function->isConst() || scope->function->isStatic());
 }
 
-void CheckOther::checkRedundantCopy()
+void CheckOtherImpl::checkRedundantCopy()
 {
     if (!mSettings->severity.isEnabled(Severity::performance) || mTokenizer->isC() || !mSettings->certainty.isEnabled(Certainty::inconclusive))
         return;
 
-    logChecker("CheckOther::checkRedundantCopy"); // c++,performance,inconclusive
+    logChecker("CheckOtherImpl::checkRedundantCopy"); // c++,performance,inconclusive
 
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
 
@@ -3421,7 +3421,7 @@ void CheckOther::checkRedundantCopy()
     }
 }
 
-void CheckOther::redundantCopyError(const Token *tok,const std::string& varname)
+void CheckOtherImpl::redundantCopyError(const Token *tok,const std::string& varname)
 {
     reportError(tok, Severity::performance, "redundantCopyLocalConst",
                 "$symbol:" + varname + "\n"
@@ -3441,11 +3441,11 @@ static bool isNegative(const Token *tok, const Settings &settings)
     return tok->valueType() && tok->valueType()->sign == ValueType::SIGNED && tok->getValueLE(-1LL, settings);
 }
 
-void CheckOther::checkNegativeBitwiseShift()
+void CheckOtherImpl::checkNegativeBitwiseShift()
 {
     const bool portability = mSettings->severity.isEnabled(Severity::portability);
 
-    logChecker("CheckOther::checkNegativeBitwiseShift");
+    logChecker("CheckOtherImpl::checkNegativeBitwiseShift");
 
     for (const Token* tok = mTokenizer->tokens(); tok; tok = tok->next()) {
         tok = skipUnreachableBranch(tok);
@@ -3483,7 +3483,7 @@ void CheckOther::checkNegativeBitwiseShift()
 }
 
 
-void CheckOther::negativeBitwiseShiftError(const Token *tok, int op)
+void CheckOtherImpl::negativeBitwiseShiftError(const Token *tok, int op)
 {
     if (op == 1)
         // LHS - this is used by intention in various software, if it
@@ -3497,7 +3497,7 @@ void CheckOther::negativeBitwiseShiftError(const Token *tok, int op)
 //---------------------------------------------------------------------------
 // Check for incompletely filled buffers.
 //---------------------------------------------------------------------------
-void CheckOther::checkIncompleteArrayFill()
+void CheckOtherImpl::checkIncompleteArrayFill()
 {
     if (!mSettings->certainty.isEnabled(Certainty::inconclusive))
         return;
@@ -3506,7 +3506,7 @@ void CheckOther::checkIncompleteArrayFill()
     if (!printPortability && !printWarning)
         return;
 
-    logChecker("CheckOther::checkIncompleteArrayFill"); // warning,portability,inconclusive
+    logChecker("CheckOtherImpl::checkIncompleteArrayFill"); // warning,portability,inconclusive
 
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
 
@@ -3546,7 +3546,7 @@ void CheckOther::checkIncompleteArrayFill()
     }
 }
 
-void CheckOther::incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean)
+void CheckOtherImpl::incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean)
 {
     if (boolean)
         reportError(tok, Severity::portability, "incompleteArrayFill",
@@ -3566,12 +3566,12 @@ void CheckOther::incompleteArrayFillError(const Token* tok, const std::string& b
 // Detect NULL being passed to variadic function.
 //---------------------------------------------------------------------------
 
-void CheckOther::checkVarFuncNullUB()
+void CheckOtherImpl::checkVarFuncNullUB()
 {
     if (!mSettings->severity.isEnabled(Severity::portability))
         return;
 
-    logChecker("CheckOther::checkVarFuncNullUB"); // portability
+    logChecker("CheckOtherImpl::checkVarFuncNullUB"); // portability
 
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope * scope : symbolDatabase->functionScopes) {
@@ -3604,7 +3604,7 @@ void CheckOther::checkVarFuncNullUB()
     }
 }
 
-void CheckOther::varFuncNullUBError(const Token *tok)
+void CheckOtherImpl::varFuncNullUBError(const Token *tok)
 {
     reportError(tok,
                 Severity::portability,
@@ -3651,12 +3651,12 @@ void CheckOther::varFuncNullUBError(const Token *tok)
                 "}", CWE475, Certainty::normal);
 }
 
-void CheckOther::checkRedundantPointerOp()
+void CheckOtherImpl::checkRedundantPointerOp()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("redundantPointerOp"))
         return;
 
-    logChecker("CheckOther::checkRedundantPointerOp"); // style
+    logChecker("CheckOtherImpl::checkRedundantPointerOp"); // style
 
     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
         if (tok->isExpandedMacro() && tok->str() == "(")
@@ -3690,20 +3690,20 @@ void CheckOther::checkRedundantPointerOp()
     }
 }
 
-void CheckOther::redundantPointerOpError(const Token* tok, const std::string &varname, bool inconclusive, bool addressOfDeref)
+void CheckOtherImpl::redundantPointerOpError(const Token* tok, const std::string &varname, bool inconclusive, bool addressOfDeref)
 {
     std::string msg = "$symbol:" + varname + "\nRedundant pointer operation on '$symbol' - it's already a ";
     msg += addressOfDeref ? "pointer." : "variable.";
     reportError(tok, Severity::style, "redundantPointerOp", msg, CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckOther::checkInterlockedDecrement()
+void CheckOtherImpl::checkInterlockedDecrement()
 {
     if (!mSettings->platform.isWindows()) {
         return;
     }
 
-    logChecker("CheckOther::checkInterlockedDecrement"); // windows-platform
+    logChecker("CheckOtherImpl::checkInterlockedDecrement"); // windows-platform
 
     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
         if (tok->isName() && Token::Match(tok, "InterlockedDecrement ( & %name% ) ; if ( %name%|!|0")) {
@@ -3737,18 +3737,18 @@ void CheckOther::checkInterlockedDecrement()
     }
 }
 
-void CheckOther::raceAfterInterlockedDecrementError(const Token* tok)
+void CheckOtherImpl::raceAfterInterlockedDecrementError(const Token* tok)
 {
     reportError(tok, Severity::error, "raceAfterInterlockedDecrement",
                 "Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead.", CWE362, Certainty::normal);
 }
 
-void CheckOther::checkUnusedLabel()
+void CheckOtherImpl::checkUnusedLabel()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("unusedLabel"))
         return;
 
-    logChecker("CheckOther::checkUnusedLabel"); // style,warning
+    logChecker("CheckOtherImpl::checkUnusedLabel"); // style,warning
 
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope * scope : symbolDatabase->functionScopes) {
@@ -3766,7 +3766,7 @@ void CheckOther::checkUnusedLabel()
     }
 }
 
-void CheckOther::unusedLabelError(const Token* tok, bool inSwitch, bool hasIfdef)
+void CheckOtherImpl::unusedLabelError(const Token* tok, bool inSwitch, bool hasIfdef)
 {
     if (tok && !mSettings->severity.isEnabled(inSwitch ? Severity::warning : Severity::style) && !mSettings->isPremiumEnabled("unusedLabel"))
         return;
@@ -3860,7 +3860,7 @@ static bool checkEvaluationOrderCpp17(const Token * tok, const Token * tok2, con
     return foundUndefined || foundUnspecified;
 }
 
-void CheckOther::checkEvaluationOrder()
+void CheckOtherImpl::checkEvaluationOrder()
 {
     logChecker("CheckOther::checkEvaluationOrder");
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -3922,7 +3922,7 @@ void CheckOther::checkEvaluationOrder()
     }
 }
 
-void CheckOther::unknownEvaluationOrder(const Token* tok, bool isUnspecifiedBehavior)
+void CheckOtherImpl::unknownEvaluationOrder(const Token* tok, bool isUnspecifiedBehavior)
 {
     isUnspecifiedBehavior ?
     reportError(tok, Severity::portability, "unknownEvaluationOrder",
@@ -3931,13 +3931,13 @@ void CheckOther::unknownEvaluationOrder(const Token* tok, bool isUnspecifiedBeha
                     "Expression '" + (tok ? tok->expressionString() : std::string("x = x++;")) + "' depends on order of evaluation of side effects", CWE768, Certainty::normal);
 }
 
-void CheckOther::checkAccessOfMovedVariable()
+void CheckOtherImpl::checkAccessOfMovedVariable()
 {
     if (!mTokenizer->isCPP() || mSettings->standards.cpp < Standards::CPP11)
         return;
     if (!mSettings->isPremiumEnabled("accessMoved") && !mSettings->severity.isEnabled(Severity::warning))
         return;
-    logChecker("CheckOther::checkAccessOfMovedVariable"); // c++11,warning
+    logChecker("CheckOtherImpl::checkAccessOfMovedVariable"); // c++11,warning
     const bool reportInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope * scope : symbolDatabase->functionScopes) {
@@ -3978,7 +3978,7 @@ void CheckOther::checkAccessOfMovedVariable()
     }
 }
 
-void CheckOther::accessMovedError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive)
+void CheckOtherImpl::accessMovedError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive)
 {
     if (!tok) {
         reportError(tok, Severity::warning, "accessMoved", "Access of moved variable 'v'.", CWE672, Certainty::normal);
@@ -4007,7 +4007,7 @@ void CheckOther::accessMovedError(const Token *tok, const std::string &varname,
 
 
 
-void CheckOther::checkFuncArgNamesDifferent()
+void CheckOtherImpl::checkFuncArgNamesDifferent()
 {
     const bool style = mSettings->severity.isEnabled(Severity::style);
     const bool inconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
@@ -4016,7 +4016,7 @@ void CheckOther::checkFuncArgNamesDifferent()
     if (!(warning || (style && inconclusive)) && !mSettings->isPremiumEnabled("funcArgNamesDifferent"))
         return;
 
-    logChecker("CheckOther::checkFuncArgNamesDifferent"); // style,warning,inconclusive
+    logChecker("CheckOtherImpl::checkFuncArgNamesDifferent"); // style,warning,inconclusive
 
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     // check every function
@@ -4090,8 +4090,8 @@ void CheckOther::checkFuncArgNamesDifferent()
     }
 }
 
-void CheckOther::funcArgNamesDifferent(const std::string & functionName, nonneg int index,
-                                       const Token* declaration, const Token* definition)
+void CheckOtherImpl::funcArgNamesDifferent(const std::string & functionName, nonneg int index,
+                                           const Token* declaration, const Token* definition)
 {
     std::list<const Token *> tokens = { declaration,definition };
     const std::string id = (declaration != nullptr) == (definition != nullptr) ? "funcArgNamesDifferent" : "funcArgNamesDifferentUnnamed";
@@ -4102,10 +4102,10 @@ void CheckOther::funcArgNamesDifferent(const std::string & functionName, nonneg
                 (definition ? definition->str() : "<unnamed>") + "'.", CWE628, Certainty::inconclusive);
 }
 
-void CheckOther::funcArgOrderDifferent(const std::string & functionName,
-                                       const Token* declaration, const Token* definition,
-                                       const std::vector<const Token *> & declarations,
-                                       const std::vector<const Token *> & definitions)
+void CheckOtherImpl::funcArgOrderDifferent(const std::string & functionName,
+                                           const Token* declaration, const Token* definition,
+                                           const std::vector<const Token *> & declarations,
+                                           const std::vector<const Token *> & definitions)
 {
     std::list<const Token *> tokens = {
         !declarations.empty() ? declarations[0] ? declarations[0] : declaration : nullptr,
@@ -4153,11 +4153,11 @@ static const Token *findShadowed(const Scope *scope, const Variable& var, int li
     return shadowed;
 }
 
-void CheckOther::checkShadowVariables()
+void CheckOtherImpl::checkShadowVariables()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("shadowVariable"))
         return;
-    logChecker("CheckOther::checkShadowVariables"); // style
+    logChecker("CheckOtherImpl::checkShadowVariables"); // style
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope & scope : symbolDatabase->scopeList) {
         if (!scope.isExecutable() || scope.type == ScopeType::eLambda)
@@ -4213,8 +4213,8 @@ void CheckOther::checkShadowVariables()
     }
 }
 
-void CheckOther::shadowError(const Token *shadows, const std::string &shadowsType,
-                             const Token *shadowed, const std::string &shadowedType)
+void CheckOtherImpl::shadowError(const Token *shadows, const std::string &shadowsType,
+                                 const Token *shadowed, const std::string &shadowedType)
 {
     ErrorPath errorPath;
     errorPath.emplace_back(shadowed, "Shadowed " + shadowedType);
@@ -4254,11 +4254,11 @@ static bool isVariableExprHidden(const Token* tok)
     return false;
 }
 
-void CheckOther::checkKnownArgument()
+void CheckOtherImpl::checkKnownArgument()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("knownArgument"))
         return;
-    logChecker("CheckOther::checkKnownArgument"); // style
+    logChecker("CheckOtherImpl::checkKnownArgument"); // style
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope *functionScope : symbolDatabase->functionScopes) {
         for (const Token *tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
@@ -4323,7 +4323,7 @@ void CheckOther::checkKnownArgument()
     }
 }
 
-void CheckOther::knownArgumentError(const Token *tok, const Token *ftok, const ValueFlow::Value *value, const std::string &varexpr, bool isVariableExpressionHidden)
+void CheckOtherImpl::knownArgumentError(const Token *tok, const Token *ftok, const ValueFlow::Value *value, const std::string &varexpr, bool isVariableExpressionHidden)
 {
     if (!tok) {
         reportError(tok, Severity::style, "knownArgument", "Argument 'x-x' to function 'func' is always 0. It does not matter what value 'x' has.");
@@ -4355,11 +4355,11 @@ void CheckOther::knownArgumentError(const Token *tok, const Token *ftok, const V
     reportError(std::move(errorPath), Severity::style, id, errmsg, CWE570, Certainty::normal);
 }
 
-void CheckOther::checkKnownPointerToBool()
+void CheckOtherImpl::checkKnownPointerToBool()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("knownPointerToBool"))
         return;
-    logChecker("CheckOther::checkKnownPointerToBool"); // style
+    logChecker("CheckOtherImpl::checkKnownPointerToBool"); // style
     const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope* functionScope : symbolDatabase->functionScopes) {
         for (const Token* tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
@@ -4385,7 +4385,7 @@ void CheckOther::checkKnownPointerToBool()
     }
 }
 
-void CheckOther::knownPointerToBoolError(const Token* tok, const ValueFlow::Value* value)
+void CheckOtherImpl::knownPointerToBoolError(const Token* tok, const ValueFlow::Value* value)
 {
     if (!tok) {
         reportError(tok, Severity::style, "knownPointerToBool", "Pointer expression 'p' converted to bool is always true.");
@@ -4398,9 +4398,9 @@ void CheckOther::knownPointerToBoolError(const Token* tok, const ValueFlow::Valu
     reportError(std::move(errorPath), Severity::style, "knownPointerToBool", errmsg, CWE570, Certainty::normal);
 }
 
-void CheckOther::checkComparePointers()
+void CheckOtherImpl::checkComparePointers()
 {
-    logChecker("CheckOther::checkComparePointers");
+    logChecker("CheckOtherImpl::checkComparePointers");
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope *functionScope : symbolDatabase->functionScopes) {
         for (const Token *tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
@@ -4439,7 +4439,7 @@ void CheckOther::checkComparePointers()
     }
 }
 
-void CheckOther::comparePointersError(const Token *tok, const ValueFlow::Value *v1, const ValueFlow::Value *v2)
+void CheckOtherImpl::comparePointersError(const Token *tok, const ValueFlow::Value *v1, const ValueFlow::Value *v2)
 {
     ErrorPath errorPath;
     std::string verb = "Comparing";
@@ -4459,12 +4459,12 @@ void CheckOther::comparePointersError(const Token *tok, const ValueFlow::Value *
         std::move(errorPath), Severity::error, id, verb + " pointers that point to different objects", CWE758, Certainty::normal);
 }
 
-void CheckOther::checkModuloOfOne()
+void CheckOtherImpl::checkModuloOfOne()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("moduloofone"))
         return;
 
-    logChecker("CheckOther::checkModuloOfOne"); // style
+    logChecker("CheckOtherImpl::checkModuloOfOne"); // style
 
     for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
         if (!tok->astOperand2() || !tok->astOperand1())
@@ -4481,7 +4481,7 @@ void CheckOther::checkModuloOfOne()
     }
 }
 
-void CheckOther::checkModuloOfOneError(const Token *tok)
+void CheckOtherImpl::checkModuloOfOneError(const Token *tok)
 {
     reportError(tok, Severity::style, "moduloofone", "Modulo of one is always equal to zero");
 }
@@ -4569,7 +4569,7 @@ static bool isZeroInitializer(const Token *tok)
 }
 
 
-void CheckOther::checkUnionZeroInit()
+void CheckOtherImpl::checkUnionZeroInit()
 {
     if (!mSettings->severity.isEnabled(Severity::portability))
         return;
@@ -4607,8 +4607,8 @@ void CheckOther::checkUnionZeroInit()
     }
 }
 
-void CheckOther::unionZeroInitError(const Token *tok,
-                                    const UnionMember& largestMember)
+void CheckOtherImpl::unionZeroInitError(const Token *tok,
+                                        const UnionMember& largestMember)
 {
     reportError(tok, Severity::portability, "UnionZeroInit",
                 (tok != nullptr ? "$symbol:" + tok->str() + "\n" : "") +
@@ -4679,9 +4679,9 @@ static bool getBufAndOffset(const Token *expr, const Token *&buf, MathLib::bigin
     return true;
 }
 
-void CheckOther::checkOverlappingWrite()
+void CheckOtherImpl::checkOverlappingWrite()
 {
-    logChecker("CheckOther::checkOverlappingWrite");
+    logChecker("CheckOtherImpl::checkOverlappingWrite");
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
     for (const Scope *functionScope : symbolDatabase->functionScopes) {
         for (const Token *tok = functionScope->bodyStart; tok != functionScope->bodyEnd; tok = tok->next()) {
@@ -4777,19 +4777,19 @@ void CheckOther::checkOverlappingWrite()
     }
 }
 
-void CheckOther::overlappingWriteUnion(const Token *tok)
+void CheckOtherImpl::overlappingWriteUnion(const Token *tok)
 {
     reportError(tok, Severity::error, "overlappingWriteUnion", "Overlapping read/write of union is undefined behavior");
 }
 
-void CheckOther::overlappingWriteFunction(const Token *tok, const std::string& funcname)
+void CheckOtherImpl::overlappingWriteFunction(const Token *tok, const std::string& funcname)
 {
     reportError(tok, Severity::error, "overlappingWriteFunction", "Overlapping read/write in " + funcname + "() is undefined behavior");
 }
 
 void CheckOther::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    CheckOther checkOther(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckOtherImpl checkOther(&tokenizer, &tokenizer.getSettings(), errorLogger);
 
     // Checks
     checkOther.warningOldStylePointerCast();
@@ -4841,7 +4841,7 @@ void CheckOther::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 
 void CheckOther::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckOther c(nullptr, settings, errorLogger);
+    CheckOtherImpl c(nullptr, settings, errorLogger);
 
     // error
     c.zerodivError(nullptr, nullptr);
diff --git a/lib/checkother.h b/lib/checkother.h
index f779141f499..733b806fafd 100644
--- a/lib/checkother.h
+++ b/lib/checkother.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 #include "errortypes.h"
 
@@ -55,7 +56,7 @@ class CPPCHECKLIB CheckOther : public Check {
 
 public:
     /** @brief This constructor is used when registering the CheckClass */
-    CheckOther() : Check(myName()) {}
+    CheckOther() : Check("Other") {}
 
     /** Is expression a comparison that checks if a nonzero (unsigned/pointer) expression is less than zero? */
     static bool comparisonNonZeroExpressionLessThanZero(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr, bool suppress = false);
@@ -64,14 +65,77 @@ class CPPCHECKLIB CheckOther : public Check {
     static bool testIfNonZeroExpressionIsPositive(const Token *tok, const ValueFlow::Value *&zeroValue, const Token *&nonZeroExpr);
 
 private:
-    /** @brief This constructor is used when running checks. */
-    CheckOther(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
-
     /** @brief Run checks against the normal token list */
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+
+    std::string classInfo() const override {
+        return "Other checks\n"
+
+               // error
+               "- division with zero\n"
+               "- scoped object destroyed immediately after construction\n"
+               "- assignment in an assert statement\n"
+               "- free() or delete of an invalid memory location\n"
+               "- bitwise operation with negative right operand\n"
+               "- cast the return values of getc(),fgetc() and getchar() to character and compare it to EOF\n"
+               "- race condition with non-interlocked access after InterlockedDecrement() call\n"
+               "- expression 'x = x++;' depends on order of evaluation of side effects\n"
+               "- overlapping write of union\n"
+
+               // warning
+               "- either division by zero or useless condition\n"
+               "- access of moved or forwarded variable.\n"
+
+               // performance
+               "- redundant data copying for const variable\n"
+               "- subsequent assignment or copying to a variable or buffer\n"
+               "- passing parameter by value\n"
+
+               // portability
+               "- Passing NULL pointer to function with variable number of arguments leads to UB.\n"
+
+               // style
+               "- C-style pointer cast in C++ code\n"
+               "- casting between incompatible pointer types\n"
+               "- [Incomplete statement](IncompleteStatement)\n"
+               "- [check how signed char variables are used](CharVar)\n"
+               "- variable scope can be limited\n"
+               "- unusual pointer arithmetic. For example: \"abc\" + 'd'\n"
+               "- redundant assignment, increment, or bitwise operation in a switch statement\n"
+               "- redundant strcpy in a switch statement\n"
+               "- Suspicious case labels in switch()\n"
+               "- assignment of a variable to itself\n"
+               "- Comparison of values leading always to true or false\n"
+               "- Clarify calculation with parentheses\n"
+               "- suspicious comparison of '\\0' with a char\\* variable\n"
+               "- duplicate break statement\n"
+               "- unreachable code\n"
+               "- testing if unsigned variable is negative/positive\n"
+               "- Suspicious use of ; at the end of 'if/for/while' statement.\n"
+               "- Array filled incompletely using memset/memcpy/memmove.\n"
+               "- NaN (not a number) value used in arithmetic expression.\n"
+               "- comma in return statement (the comma can easily be misread as a semicolon).\n"
+               "- prefer erfc, expm1 or log1p to avoid loss of precision.\n"
+               "- identical code in both branches of if/else or ternary operator.\n"
+               "- redundant pointer operation on pointer like &\\*some_ptr.\n"
+               "- find unused 'goto' labels.\n"
+               "- function declaration and definition argument names different.\n"
+               "- function declaration and definition argument order different.\n"
+               "- shadow variable.\n"
+               "- variable can be declared const.\n"
+               "- calculating modulo of one.\n"
+               "- known function argument, suspicious calculation.\n";
+    }
+};
+
+class CPPCHECKLIB CheckOtherImpl : public CheckImpl {
+public:
+    /** @brief This constructor is used when running checks. */
+    CheckOtherImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     /** @brief Clarify calculation for ".. a * b ? .." */
     void clarifyCalculation();
 
@@ -265,74 +329,6 @@ class CPPCHECKLIB CheckOther : public Check {
     void checkModuloOfOneError(const Token *tok);
     void unionZeroInitError(const Token *tok, const UnionMember& largestMember);
 
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "Other";
-    }
-
-    std::string classInfo() const override {
-        return "Other checks\n"
-
-               // error
-               "- division with zero\n"
-               "- scoped object destroyed immediately after construction\n"
-               "- assignment in an assert statement\n"
-               "- free() or delete of an invalid memory location\n"
-               "- bitwise operation with negative right operand\n"
-               "- cast the return values of getc(),fgetc() and getchar() to character and compare it to EOF\n"
-               "- race condition with non-interlocked access after InterlockedDecrement() call\n"
-               "- expression 'x = x++;' depends on order of evaluation of side effects\n"
-               "- overlapping write of union\n"
-
-               // warning
-               "- either division by zero or useless condition\n"
-               "- access of moved or forwarded variable.\n"
-               "- potentially dangerous C style type cast of pointer/reference to object.\n"
-
-               // performance
-               "- redundant data copying for const variable\n"
-               "- subsequent assignment or copying to a variable or buffer\n"
-               "- passing parameter by value\n"
-
-               // portability
-               "- Passing NULL pointer to function with variable number of arguments leads to UB.\n"
-               "- Casting non-zero integer literal in decimal or octal format to pointer.\n"
-               "- Incorrect zero initialization of unions can lead to access of uninitialized memory.\n"
-
-               // style
-               "- C-style pointer cast in C++ code\n"
-               "- casting between incompatible pointer types\n"
-               "- [Incomplete statement](IncompleteStatement)\n"
-               "- [check how signed char variables are used](CharVar)\n"
-               "- variable scope can be limited\n"
-               "- unusual pointer arithmetic. For example: \"abc\" + 'd'\n"
-               "- redundant assignment, increment, or bitwise operation in a switch statement\n"
-               "- redundant strcpy in a switch statement\n"
-               "- Suspicious case labels in switch()\n"
-               "- assignment of a variable to itself\n"
-               "- Comparison of values leading always to true or false\n"
-               "- Clarify calculation with parentheses\n"
-               "- suspicious comparison of '\\0' with a char\\* variable\n"
-               "- duplicate break statement\n"
-               "- unreachable code\n"
-               "- testing if unsigned variable is negative/positive\n"
-               "- Suspicious use of ; at the end of 'if/for/while' statement.\n"
-               "- Array filled incompletely using memset/memcpy/memmove.\n"
-               "- NaN (not a number) value used in arithmetic expression.\n"
-               "- comma in return statement (the comma can easily be misread as a semicolon).\n"
-               "- prefer erfc, expm1 or log1p to avoid loss of precision.\n"
-               "- identical code in both branches of if/else or ternary operator.\n"
-               "- redundant pointer operation on pointer like &\\*some_ptr.\n"
-               "- find unused 'goto' labels.\n"
-               "- function declaration and definition argument names different.\n"
-               "- function declaration and definition argument order different.\n"
-               "- shadow variable.\n"
-               "- variable can be declared const.\n"
-               "- calculating modulo of one.\n"
-               "- known function argument, suspicious calculation.\n";
-    }
-
     bool diag(const Token* tok) {
         return !mRedundantAssignmentDiag.emplace(tok).second;
     }
diff --git a/lib/checkpostfixoperator.cpp b/lib/checkpostfixoperator.cpp
index d771177b2d2..0b02313b672 100644
--- a/lib/checkpostfixoperator.cpp
+++ b/lib/checkpostfixoperator.cpp
@@ -37,8 +37,7 @@
 // CWE ids used
 static const CWE CWE398(398U);   // Indicator of Poor Code Quality
 
-
-void CheckPostfixOperator::postfixOperator()
+void CheckPostfixOperatorImpl::postfixOperator()
 {
     if (!mSettings->severity.isEnabled(Severity::performance))
         return;
@@ -84,7 +83,7 @@ void CheckPostfixOperator::postfixOperator()
 //---------------------------------------------------------------------------
 
 
-void CheckPostfixOperator::postfixOperatorError(const Token *tok)
+void CheckPostfixOperatorImpl::postfixOperatorError(const Token *tok)
 {
     reportError(tok, Severity::performance, "postfixOperator",
                 "Prefer prefix ++/-- operators for non-primitive types.\n"
@@ -100,12 +99,12 @@ void CheckPostfixOperator::runChecks(const Tokenizer &tokenizer, ErrorLogger *er
     if (tokenizer.isC())
         return;
 
-    CheckPostfixOperator checkPostfixOperator(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckPostfixOperatorImpl checkPostfixOperator(&tokenizer, &tokenizer.getSettings(), errorLogger);
     checkPostfixOperator.postfixOperator();
 }
 
 void CheckPostfixOperator::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckPostfixOperator c(nullptr, settings, errorLogger);
+    CheckPostfixOperatorImpl c(nullptr, settings, errorLogger);
     c.postfixOperatorError(nullptr);
 }
diff --git a/lib/checkpostfixoperator.h b/lib/checkpostfixoperator.h
index c9f58a7e143..03ab54eed11 100644
--- a/lib/checkpostfixoperator.h
+++ b/lib/checkpostfixoperator.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <string>
@@ -44,30 +45,28 @@ class CPPCHECKLIB CheckPostfixOperator : public Check {
 
 public:
     /** This constructor is used when registering the CheckPostfixOperator */
-    CheckPostfixOperator() : Check(myName()) {}
+    CheckPostfixOperator() : Check("Using postfix operators") {}
 
 private:
-    /** This constructor is used when running checks. */
-    CheckPostfixOperator(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+    std::string classInfo() const override {
+        return "Warn if using postfix operators ++ or -- rather than prefix operator\n";
+    }
+};
+
+class CPPCHECKLIB CheckPostfixOperatorImpl : public CheckImpl {
+public:
+    /** This constructor is used when running checks. */
+    CheckPostfixOperatorImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     /** Check postfix operators */
     void postfixOperator();
 
     /** Report Error */
     void postfixOperatorError(const Token *tok);
-
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "Using postfix operators";
-    }
-
-    std::string classInfo() const override {
-        return "Warn if using postfix operators ++ or -- rather than prefix operator\n";
-    }
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checksizeof.cpp b/lib/checksizeof.cpp
index 134cca92b7f..8e0f247f2c7 100644
--- a/lib/checksizeof.cpp
+++ b/lib/checksizeof.cpp
@@ -39,7 +39,7 @@ static const CWE CWE467(467U);   // Use of sizeof() on a Pointer Type
 static const CWE CWE682(682U);   // Incorrect Calculation
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-void CheckSizeof::checkSizeofForNumericParameter()
+void CheckSizeofImpl::checkSizeofForNumericParameter()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -57,7 +57,7 @@ void CheckSizeof::checkSizeofForNumericParameter()
     }
 }
 
-void CheckSizeof::sizeofForNumericParameterError(const Token *tok)
+void CheckSizeofImpl::sizeofForNumericParameterError(const Token *tok)
 {
     reportError(tok, Severity::warning,
                 "sizeofwithnumericparameter", "Suspicious usage of 'sizeof' with a numeric constant as parameter.\n"
@@ -69,7 +69,7 @@ void CheckSizeof::sizeofForNumericParameterError(const Token *tok)
 
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-void CheckSizeof::checkSizeofForArrayParameter()
+void CheckSizeofImpl::checkSizeofForArrayParameter()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -94,7 +94,7 @@ void CheckSizeof::checkSizeofForArrayParameter()
     }
 }
 
-void CheckSizeof::sizeofForArrayParameterError(const Token *tok)
+void CheckSizeofImpl::sizeofForArrayParameterError(const Token *tok)
 {
     reportError(tok, Severity::warning,
                 "sizeofwithsilentarraypointer", "Using 'sizeof' on array given as function argument "
@@ -110,7 +110,7 @@ void CheckSizeof::sizeofForArrayParameterError(const Token *tok)
                 );
 }
 
-void CheckSizeof::checkSizeofForPointerSize()
+void CheckSizeofImpl::checkSizeofForPointerSize()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -262,7 +262,7 @@ void CheckSizeof::checkSizeofForPointerSize()
     }
 }
 
-void CheckSizeof::sizeofForPointerError(const Token *tok, const std::string &varname)
+void CheckSizeofImpl::sizeofForPointerError(const Token *tok, const std::string &varname)
 {
     reportError(tok, Severity::warning, "pointerSize",
                 "Size of pointer '" + varname + "' used instead of size of its data.\n"
@@ -271,7 +271,7 @@ void CheckSizeof::sizeofForPointerError(const Token *tok, const std::string &var
                 "write 'sizeof(*" + varname + ")'.", CWE467, Certainty::normal);
 }
 
-void CheckSizeof::divideBySizeofError(const Token *tok, const std::string &memfunc)
+void CheckSizeofImpl::divideBySizeofError(const Token *tok, const std::string &memfunc)
 {
     reportError(tok, Severity::warning, "sizeofDivisionMemfunc",
                 "Division by result of sizeof(). " + memfunc + "() expects a size in bytes, did you intend to multiply instead?", CWE682, Certainty::normal);
@@ -279,7 +279,7 @@ void CheckSizeof::divideBySizeofError(const Token *tok, const std::string &memfu
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
-void CheckSizeof::sizeofsizeof()
+void CheckSizeofImpl::sizeofsizeof()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -294,7 +294,7 @@ void CheckSizeof::sizeofsizeof()
     }
 }
 
-void CheckSizeof::sizeofsizeofError(const Token *tok)
+void CheckSizeofImpl::sizeofsizeofError(const Token *tok)
 {
     reportError(tok, Severity::warning,
                 "sizeofsizeof", "Calling 'sizeof' on 'sizeof'.\n"
@@ -305,7 +305,7 @@ void CheckSizeof::sizeofsizeofError(const Token *tok)
 
 //-----------------------------------------------------------------------------
 
-void CheckSizeof::sizeofCalculation()
+void CheckSizeofImpl::sizeofCalculation()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -343,7 +343,7 @@ void CheckSizeof::sizeofCalculation()
     }
 }
 
-void CheckSizeof::sizeofCalculationError(const Token *tok, bool inconclusive)
+void CheckSizeofImpl::sizeofCalculationError(const Token *tok, bool inconclusive)
 {
     reportError(tok, Severity::warning,
                 "sizeofCalculation", "Found calculation inside sizeof().", CWE682, inconclusive ? Certainty::inconclusive : Certainty::normal);
@@ -351,7 +351,7 @@ void CheckSizeof::sizeofCalculationError(const Token *tok, bool inconclusive)
 
 //-----------------------------------------------------------------------------
 
-void CheckSizeof::sizeofFunction()
+void CheckSizeofImpl::sizeofFunction()
 {
     if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("sizeofFunctionCall"))
         return;
@@ -385,7 +385,7 @@ void CheckSizeof::sizeofFunction()
     }
 }
 
-void CheckSizeof::sizeofFunctionError(const Token *tok)
+void CheckSizeofImpl::sizeofFunctionError(const Token *tok)
 {
     reportError(tok, Severity::warning,
                 "sizeofFunctionCall", "Found function call inside sizeof().", CWE682, Certainty::normal);
@@ -394,7 +394,7 @@ void CheckSizeof::sizeofFunctionError(const Token *tok)
 //-----------------------------------------------------------------------------
 // Check for code like sizeof()*sizeof() or sizeof(ptr)/value
 //-----------------------------------------------------------------------------
-void CheckSizeof::suspiciousSizeofCalculation()
+void CheckSizeofImpl::suspiciousSizeofCalculation()
 {
     if (!mSettings->severity.isEnabled(Severity::warning) || !mSettings->certainty.isEnabled(Certainty::inconclusive))
         return;
@@ -424,13 +424,13 @@ void CheckSizeof::suspiciousSizeofCalculation()
     }
 }
 
-void CheckSizeof::multiplySizeofError(const Token *tok)
+void CheckSizeofImpl::multiplySizeofError(const Token *tok)
 {
     reportError(tok, Severity::warning,
                 "multiplySizeof", "Multiplying sizeof() with sizeof() indicates a logic error.", CWE682, Certainty::inconclusive);
 }
 
-void CheckSizeof::divideSizeofError(const Token *tok)
+void CheckSizeofImpl::divideSizeofError(const Token *tok)
 {
     reportError(tok, Severity::warning,
                 "divideSizeof", "Division of result of sizeof() on pointer type.\n"
@@ -438,7 +438,7 @@ void CheckSizeof::divideSizeofError(const Token *tok)
                 "not the size of the memory area it points to.", CWE682, Certainty::inconclusive);
 }
 
-void CheckSizeof::sizeofVoid()
+void CheckSizeofImpl::sizeofVoid()
 {
     if (!mSettings->severity.isEnabled(Severity::portability))
         return;
@@ -476,21 +476,21 @@ void CheckSizeof::sizeofVoid()
     }
 }
 
-void CheckSizeof::sizeofVoidError(const Token *tok)
+void CheckSizeofImpl::sizeofVoidError(const Token *tok)
 {
     const std::string message = "Behaviour of 'sizeof(void)' is not covered by the ISO C standard.";
     const std::string verbose = message + " A value for 'sizeof(void)' is defined only as part of a GNU C extension, which defines 'sizeof(void)' to be 1.";
     reportError(tok, Severity::portability, "sizeofVoid", message + "\n" + verbose, CWE682, Certainty::normal);
 }
 
-void CheckSizeof::sizeofDereferencedVoidPointerError(const Token *tok, const std::string &varname)
+void CheckSizeofImpl::sizeofDereferencedVoidPointerError(const Token *tok, const std::string &varname)
 {
     const std::string message = "'*" + varname + "' is of type 'void', the behaviour of 'sizeof(void)' is not covered by the ISO C standard.";
     const std::string verbose = message + " A value for 'sizeof(void)' is defined only as part of a GNU C extension, which defines 'sizeof(void)' to be 1.";
     reportError(tok, Severity::portability, "sizeofDereferencedVoidPointer", message + "\n" + verbose, CWE682, Certainty::normal);
 }
 
-void CheckSizeof::arithOperationsOnVoidPointerError(const Token* tok, const std::string &varname, const std::string &vartype)
+void CheckSizeofImpl::arithOperationsOnVoidPointerError(const Token* tok, const std::string &varname, const std::string &vartype)
 {
     const std::string message = "'$symbol' is of type '" + vartype + "'. When using void pointers in calculations, the behaviour is undefined.";
     const std::string verbose = message + " Arithmetic operations on 'void *' is a GNU C extension, which defines the 'sizeof(void)' to be 1.";
@@ -499,7 +499,7 @@ void CheckSizeof::arithOperationsOnVoidPointerError(const Token* tok, const std:
 
 void CheckSizeof::runChecks(const Tokenizer& tokenizer, ErrorLogger* errorLogger)
 {
-    CheckSizeof checkSizeof(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckSizeofImpl checkSizeof(&tokenizer, &tokenizer.getSettings(), errorLogger);
 
     // Checks
     checkSizeof.sizeofsizeof();
@@ -514,7 +514,7 @@ void CheckSizeof::runChecks(const Tokenizer& tokenizer, ErrorLogger* errorLogger
 
 void CheckSizeof::getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const
 {
-    CheckSizeof c(nullptr, settings, errorLogger);
+    CheckSizeofImpl c(nullptr, settings, errorLogger);
     c.sizeofForArrayParameterError(nullptr);
     c.sizeofForPointerError(nullptr, "varname");
     c.divideBySizeofError(nullptr, "memset");
diff --git a/lib/checksizeof.h b/lib/checksizeof.h
index 4c10ca88dac..0ec4b298de5 100644
--- a/lib/checksizeof.h
+++ b/lib/checksizeof.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <string>
@@ -41,16 +42,33 @@ class Tokenizer;
 class CPPCHECKLIB CheckSizeof : public Check {
 public:
     /** @brief This constructor is used when registering the CheckClass */
-    CheckSizeof() : Check(myName()) {}
+    CheckSizeof() : Check("Sizeof") {}
 
 private:
-    /** @brief This constructor is used when running checks. */
-    CheckSizeof(const Tokenizer* tokenizer, const Settings* settings, ErrorLogger* errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     /** @brief Run checks against the normal token list */
     void runChecks(const Tokenizer& tokenizer, ErrorLogger* errorLogger) override;
 
+    void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const override;
+
+    std::string classInfo() const override {
+        return "sizeof() usage checks\n"
+               "- sizeof for array given as function argument\n"
+               "- sizeof for numeric given as function argument\n"
+               "- using sizeof(pointer) instead of the size of pointed data\n"
+               "- look for 'sizeof sizeof ..'\n"
+               "- look for calculations inside sizeof()\n"
+               "- look for function calls inside sizeof()\n"
+               "- look for suspicious calculations with sizeof()\n"
+               "- using 'sizeof(void)' which is undefined\n";
+    }
+};
+
+class CPPCHECKLIB CheckSizeofImpl : public CheckImpl {
+public:
+    /** @brief This constructor is used when running checks. */
+    CheckSizeofImpl(const Tokenizer* tokenizer, const Settings* settings, ErrorLogger* errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     /** @brief %Check for 'sizeof sizeof ..' */
     void sizeofsizeof();
 
@@ -88,24 +106,6 @@ class CPPCHECKLIB CheckSizeof : public Check {
     void sizeofVoidError(const Token *tok);
     void sizeofDereferencedVoidPointerError(const Token *tok, const std::string &varname);
     void arithOperationsOnVoidPointerError(const Token* tok, const std::string &varname, const std::string &vartype);
-
-    void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const override;
-
-    static std::string myName() {
-        return "Sizeof";
-    }
-
-    std::string classInfo() const override {
-        return "sizeof() usage checks\n"
-               "- sizeof for array given as function argument\n"
-               "- sizeof for numeric given as function argument\n"
-               "- using sizeof(pointer) instead of the size of pointed data\n"
-               "- look for 'sizeof sizeof ..'\n"
-               "- look for calculations inside sizeof()\n"
-               "- look for function calls inside sizeof()\n"
-               "- look for suspicious calculations with sizeof()\n"
-               "- using 'sizeof(void)' which is undefined\n";
-    }
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp
index b1543f4af37..616f8603afe 100644
--- a/lib/checkstl.cpp
+++ b/lib/checkstl.cpp
@@ -127,7 +127,7 @@ static const Token* getContainerFromSize(const Library::Container* container, co
     return nullptr;
 }
 
-void CheckStl::outOfBounds()
+void CheckStlImpl::outOfBounds()
 {
     logChecker("CheckStl::outOfBounds");
 
@@ -215,7 +215,7 @@ static std::string indexValueString(const ValueFlow::Value& indexValue, const st
     return indexString;
 }
 
-void CheckStl::outOfBoundsError(const Token *tok, const std::string &containerName, const ValueFlow::Value *containerSize, const std::string &index, const ValueFlow::Value *indexValue)
+void CheckStlImpl::outOfBoundsError(const Token *tok, const std::string &containerName, const ValueFlow::Value *containerSize, const std::string &index, const ValueFlow::Value *indexValue)
 {
     // Do not warn if both the container size and index value are possible
     if (containerSize && indexValue && containerSize->isPossible() && indexValue->isPossible())
@@ -274,7 +274,7 @@ void CheckStl::outOfBoundsError(const Token *tok, const std::string &containerNa
                 (containerSize && containerSize->isInconclusive()) || (indexValue && indexValue->isInconclusive()) ? Certainty::inconclusive : Certainty::normal);
 }
 
-bool CheckStl::isContainerSize(const Token *containerToken, const Token *expr) const
+bool CheckStlImpl::isContainerSize(const Token *containerToken, const Token *expr) const
 {
     if (!Token::simpleMatch(expr, "( )"))
         return false;
@@ -285,7 +285,7 @@ bool CheckStl::isContainerSize(const Token *containerToken, const Token *expr) c
     return containerToken->valueType()->container->getYield(expr->strAt(-1)) == Library::Container::Yield::SIZE;
 }
 
-bool CheckStl::isContainerSizeGE(const Token * containerToken, const Token *expr) const
+bool CheckStlImpl::isContainerSizeGE(const Token * containerToken, const Token *expr) const
 {
     if (!expr)
         return false;
@@ -314,7 +314,7 @@ bool CheckStl::isContainerSizeGE(const Token * containerToken, const Token *expr
     return false;
 }
 
-void CheckStl::outOfBoundsIndexExpression()
+void CheckStlImpl::outOfBoundsIndexExpression()
 {
     logChecker("CheckStl::outOfBoundsIndexExpression");
     for (const Scope *function : mTokenizer->getSymbolDatabase()->functionScopes) {
@@ -334,7 +334,7 @@ void CheckStl::outOfBoundsIndexExpression()
     }
 }
 
-void CheckStl::outOfBoundsIndexExpressionError(const Token *tok, const Token *index)
+void CheckStlImpl::outOfBoundsIndexExpressionError(const Token *tok, const Token *index)
 {
     const std::string varname = tok ? tok->str() : std::string("var");
     const std::string i = index ? index->expressionString() : (varname + ".size()");
@@ -352,12 +352,12 @@ void CheckStl::outOfBoundsIndexExpressionError(const Token *tok, const Token *in
 
 
 // Error message for bad iterator usage..
-void CheckStl::invalidIteratorError(const Token *tok, const std::string &iteratorName)
+void CheckStlImpl::invalidIteratorError(const Token *tok, const std::string &iteratorName)
 {
     reportError(tok, Severity::error, "invalidIterator1", "$symbol:"+iteratorName+"\nInvalid iterator: $symbol", CWE664, Certainty::normal);
 }
 
-void CheckStl::iteratorsError(const Token* tok, const std::string& containerName1, const std::string& containerName2)
+void CheckStlImpl::iteratorsError(const Token* tok, const std::string& containerName1, const std::string& containerName2)
 {
     reportError(tok, Severity::error, "iterators1",
                 "$symbol:" + containerName1 + "\n"
@@ -365,7 +365,7 @@ void CheckStl::iteratorsError(const Token* tok, const std::string& containerName
                 "Same iterator is used with different containers '" + containerName1 + "' and '" + containerName2 + "'.", CWE664, Certainty::normal);
 }
 
-void CheckStl::iteratorsError(const Token* tok, const Token* containerTok, const std::string& containerName)
+void CheckStlImpl::iteratorsError(const Token* tok, const Token* containerTok, const std::string& containerName)
 {
     std::list<const Token*> callstack = { tok, containerTok };
     reportError(callstack,
@@ -379,7 +379,7 @@ void CheckStl::iteratorsError(const Token* tok, const Token* containerTok, const
 }
 
 // Error message used when dereferencing an iterator that has been erased..
-void CheckStl::dereferenceErasedError(const Token *erased, const Token* deref, const std::string &itername, bool inconclusive)
+void CheckStlImpl::dereferenceErasedError(const Token *erased, const Token* deref, const std::string &itername, bool inconclusive)
 {
     if (erased) {
         std::list<const Token*> callstack = { deref, erased };
@@ -449,7 +449,7 @@ static bool isVector(const Token* tok)
     return Token::simpleMatch(decltok, "std :: vector");
 }
 
-void CheckStl::iterators()
+void CheckStlImpl::iterators()
 {
     logChecker("CheckStl::iterators");
 
@@ -634,7 +634,7 @@ void CheckStl::iterators()
     }
 }
 
-void CheckStl::mismatchingContainerIteratorError(const Token* containerTok, const Token* iterTok, const Token* containerTok2)
+void CheckStlImpl::mismatchingContainerIteratorError(const Token* containerTok, const Token* iterTok, const Token* containerTok2)
 {
     const std::string container(containerTok ? containerTok->expressionString() : std::string("v1"));
     const std::string container2(containerTok2 ? containerTok2->expressionString() : std::string("v2"));
@@ -648,7 +648,7 @@ void CheckStl::mismatchingContainerIteratorError(const Token* containerTok, cons
 }
 
 // Error message for bad iterator usage..
-void CheckStl::mismatchingContainersError(const Token* tok1, const Token* tok2)
+void CheckStlImpl::mismatchingContainersError(const Token* tok1, const Token* tok2)
 {
     const std::string expr1(tok1 ? tok1->expressionString() : std::string("v1"));
     const std::string expr2(tok2 ? tok2->expressionString() : std::string("v2"));
@@ -660,7 +660,7 @@ void CheckStl::mismatchingContainersError(const Token* tok1, const Token* tok2)
                 Certainty::normal);
 }
 
-void CheckStl::mismatchingContainerExpressionError(const Token *tok1, const Token *tok2)
+void CheckStlImpl::mismatchingContainerExpressionError(const Token *tok1, const Token *tok2)
 {
     const std::string expr1(tok1 ? tok1->expressionString() : std::string("v1"));
     const std::string expr2(tok2 ? tok2->expressionString() : std::string("v2"));
@@ -669,7 +669,7 @@ void CheckStl::mismatchingContainerExpressionError(const Token *tok1, const Toke
                 expr1 + "' and '" + expr2 + "' are used together.", CWE664, Certainty::normal);
 }
 
-void CheckStl::sameIteratorExpressionError(const Token *tok)
+void CheckStlImpl::sameIteratorExpressionError(const Token *tok)
 {
     reportError(tok, Severity::style, "sameIteratorExpression", "Same iterators expression are used for algorithm.", CWE664, Certainty::normal);
 }
@@ -754,7 +754,7 @@ static ValueFlow::Value getLifetimeIteratorValue(const Token* tok, MathLib::bigi
     return ValueFlow::Value{};
 }
 
-bool CheckStl::checkIteratorPair(const Token* tok1, const Token* tok2)
+bool CheckStlImpl::checkIteratorPair(const Token* tok1, const Token* tok2)
 {
     if (!tok1)
         return false;
@@ -806,7 +806,7 @@ namespace {
     };
 }
 
-void CheckStl::mismatchingContainers()
+void CheckStlImpl::mismatchingContainers()
 {
     logChecker("CheckStl::misMatchingContainers");
 
@@ -866,7 +866,7 @@ void CheckStl::mismatchingContainers()
     }
 }
 
-void CheckStl::mismatchingContainerIterator()
+void CheckStlImpl::mismatchingContainerIterator()
 {
     logChecker("CheckStl::misMatchingContainerIterator");
 
@@ -1118,7 +1118,7 @@ static const Token* endOfExpression(const Token* tok)
     return endToken;
 }
 
-void CheckStl::invalidContainer()
+void CheckStlImpl::invalidContainer()
 {
     logChecker("CheckStl::invalidContainer");
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -1232,7 +1232,7 @@ void CheckStl::invalidContainer()
     }
 }
 
-void CheckStl::invalidContainerLoopError(const Token* tok, const Token* loopTok, ErrorPath errorPath)
+void CheckStlImpl::invalidContainerLoopError(const Token* tok, const Token* loopTok, ErrorPath errorPath)
 {
     const std::string method = tok ? tok->str() : "erase";
     errorPath.emplace_back(loopTok, "Iterating container here.");
@@ -1247,7 +1247,7 @@ void CheckStl::invalidContainerLoopError(const Token* tok, const Token* loopTok,
     reportError(std::move(errorPath), Severity::error, "invalidContainerLoop", msg, CWE664, Certainty::normal);
 }
 
-void CheckStl::invalidContainerError(const Token *tok, const ValueFlow::Value *val, ErrorPath errorPath)
+void CheckStlImpl::invalidContainerError(const Token *tok, const ValueFlow::Value *val, ErrorPath errorPath)
 {
     const bool inconclusive = val ? val->isInconclusive() : false;
     if (val)
@@ -1257,7 +1257,7 @@ void CheckStl::invalidContainerError(const Token *tok, const ValueFlow::Value *v
     reportError(std::move(errorPath), Severity::error, "invalidContainer", msg + " that may be invalid.", CWE664, inconclusive ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckStl::invalidContainerReferenceError(const Token* tok, const Token* contTok, ErrorPath errorPath)
+void CheckStlImpl::invalidContainerReferenceError(const Token* tok, const Token* contTok, ErrorPath errorPath)
 {
     std::string name = contTok ? contTok->expressionString() : "x";
     std::string msg = "Reference to " + name;
@@ -1265,7 +1265,7 @@ void CheckStl::invalidContainerReferenceError(const Token* tok, const Token* con
     reportError(std::move(errorPath), Severity::error, "invalidContainerReference", msg + " that may be invalid.", CWE664, Certainty::normal);
 }
 
-void CheckStl::stlOutOfBounds()
+void CheckStlImpl::stlOutOfBounds()
 {
     logChecker("CheckStl::stlOutOfBounds");
 
@@ -1351,7 +1351,7 @@ void CheckStl::stlOutOfBounds()
     }
 }
 
-void CheckStl::stlOutOfBoundsError(const Token *tok, const std::string &num, const std::string &var, bool at)
+void CheckStlImpl::stlOutOfBoundsError(const Token *tok, const std::string &num, const std::string &var, bool at)
 {
     if (at)
         reportError(tok, Severity::error, "stlOutOfBounds", "$symbol:" + var + "\nWhen " + num + "==$symbol.size(), $symbol.at(" + num + ") is out of bounds.", CWE788, Certainty::normal);
@@ -1359,7 +1359,7 @@ void CheckStl::stlOutOfBoundsError(const Token *tok, const std::string &num, con
         reportError(tok, Severity::error, "stlOutOfBounds", "$symbol:" + var + "\nWhen " + num + "==$symbol.size(), $symbol[" + num + "] is out of bounds.", CWE788, Certainty::normal);
 }
 
-void CheckStl::negativeIndex()
+void CheckStlImpl::negativeIndex()
 {
     logChecker("CheckStl::negativeIndex");
 
@@ -1383,7 +1383,7 @@ void CheckStl::negativeIndex()
     }
 }
 
-void CheckStl::negativeIndexError(const Token *tok, const ValueFlow::Value &index)
+void CheckStlImpl::negativeIndexError(const Token *tok, const ValueFlow::Value &index)
 {
     ErrorPath errorPath = getErrorPath(tok, &index, "Negative array index");
     std::ostringstream errmsg;
@@ -1397,7 +1397,7 @@ void CheckStl::negativeIndexError(const Token *tok, const ValueFlow::Value &inde
     reportError(std::move(errorPath), severity, "negativeContainerIndex", errmsg.str(), CWE786, certainty);
 }
 
-void CheckStl::erase()
+void CheckStlImpl::erase()
 {
     logChecker("CheckStl::erase");
 
@@ -1418,7 +1418,7 @@ void CheckStl::erase()
     }
 }
 
-void CheckStl::eraseCheckLoopVar(const Scope &scope, const Variable *var)
+void CheckStlImpl::eraseCheckLoopVar(const Scope &scope, const Variable *var)
 {
     bool inconclusiveType=false;
     if (!isIterator(var, inconclusiveType))
@@ -1462,7 +1462,7 @@ void CheckStl::eraseCheckLoopVar(const Scope &scope, const Variable *var)
     }
 }
 
-void CheckStl::stlBoundaries()
+void CheckStlImpl::stlBoundaries()
 {
     logChecker("CheckStl::stlBoundaries");
 
@@ -1487,7 +1487,7 @@ void CheckStl::stlBoundaries()
 }
 
 // Error message for bad boundary usage..
-void CheckStl::stlBoundariesError(const Token *tok)
+void CheckStlImpl::stlBoundariesError(const Token *tok)
 {
     reportError(tok, Severity::error, "stlBoundaries",
                 "Dangerous comparison using operator< on iterator.\n"
@@ -1516,7 +1516,7 @@ static bool if_findCompare(const Token * const tokBack, bool stdStringLike)
     return false;
 }
 
-void CheckStl::if_find()
+void CheckStlImpl::if_find()
 {
     const bool printWarning = mSettings->severity.isEnabled(Severity::warning);
     const bool printPerformance = mSettings->severity.isEnabled(Severity::performance);
@@ -1593,7 +1593,7 @@ void CheckStl::if_find()
 }
 
 
-void CheckStl::if_findError(const Token *tok, bool str)
+void CheckStlImpl::if_findError(const Token *tok, bool str)
 {
     if (str && mSettings->standards.cpp >= Standards::CPP20)
         reportError(tok, Severity::performance, "stlIfStrFind",
@@ -1684,7 +1684,7 @@ static const Token *findInsertValue(const Token *tok, const Token *containerTok,
     return nullptr;
 }
 
-void CheckStl::checkFindInsert()
+void CheckStlImpl::checkFindInsert()
 {
     if (!mSettings->severity.isEnabled(Severity::performance))
         return;
@@ -1730,7 +1730,7 @@ void CheckStl::checkFindInsert()
     }
 }
 
-void CheckStl::checkFindInsertError(const Token *tok)
+void CheckStlImpl::checkFindInsertError(const Token *tok)
 {
     std::string replaceExpr;
     if (tok && Token::simpleMatch(tok->astParent(), "=") && tok == tok->astParent()->astOperand2() && Token::simpleMatch(tok->astParent()->astOperand1(), "[")) {
@@ -1762,7 +1762,7 @@ static bool isCpp03ContainerSizeSlow(const Token *tok)
     return var && var->isStlType("list");
 }
 
-void CheckStl::size()
+void CheckStlImpl::size()
 {
     if (!mSettings->severity.isEnabled(Severity::performance))
         return;
@@ -1811,7 +1811,7 @@ void CheckStl::size()
     }
 }
 
-void CheckStl::sizeError(const Token *tok)
+void CheckStlImpl::sizeError(const Token *tok)
 {
     const std::string varname = tok ? tok->str() : std::string("list");
     reportError(tok, Severity::performance, "stlSize",
@@ -1823,7 +1823,7 @@ void CheckStl::sizeError(const Token *tok)
                 "guaranteed to take constant time.", CWE398, Certainty::normal);
 }
 
-void CheckStl::redundantCondition()
+void CheckStlImpl::redundantCondition()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("redundantIfRemove"))
         return;
@@ -1856,7 +1856,7 @@ void CheckStl::redundantCondition()
     }
 }
 
-void CheckStl::redundantIfRemoveError(const Token *tok)
+void CheckStlImpl::redundantIfRemoveError(const Token *tok)
 {
     reportError(tok, Severity::style, "redundantIfRemove",
                 "Redundant checking of STL container element existence before removing it.\n"
@@ -1864,7 +1864,7 @@ void CheckStl::redundantIfRemoveError(const Token *tok)
                 "It is safe to call the remove method on a non-existing element.", CWE398, Certainty::normal);
 }
 
-void CheckStl::missingComparison()
+void CheckStlImpl::missingComparison()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -1928,7 +1928,7 @@ void CheckStl::missingComparison()
     }
 }
 
-void CheckStl::missingComparisonError(const Token *incrementToken1, const Token *incrementToken2)
+void CheckStlImpl::missingComparisonError(const Token *incrementToken1, const Token *incrementToken2)
 {
     std::list<const Token*> callstack = { incrementToken1,incrementToken2 };
 
@@ -2024,7 +2024,7 @@ namespace {
     };
 }
 
-void CheckStl::string_c_str()
+void CheckStlImpl::string_c_str()
 {
     const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
     const bool printPerformance = mSettings->severity.isEnabled(Severity::performance);
@@ -2220,25 +2220,25 @@ void CheckStl::string_c_str()
     }
 }
 
-void CheckStl::string_c_strThrowError(const Token* tok)
+void CheckStlImpl::string_c_strThrowError(const Token* tok)
 {
     reportError(tok, Severity::error, "stlcstrthrow", "Dangerous usage of c_str(). The value returned by c_str() is invalid after throwing exception.\n"
                 "Dangerous usage of c_str(). The string is destroyed after the c_str() call so the thrown pointer is invalid.");
 }
 
-void CheckStl::string_c_strError(const Token* tok)
+void CheckStlImpl::string_c_strError(const Token* tok)
 {
     reportError(tok, Severity::error, "stlcstr", "Dangerous usage of c_str(). The value returned by c_str() is invalid after this call.\n"
                 "Dangerous usage of c_str(). The c_str() return value is only valid until its string is deleted.", CWE664, Certainty::normal);
 }
 
-void CheckStl::string_c_strReturn(const Token* tok)
+void CheckStlImpl::string_c_strReturn(const Token* tok)
 {
     reportError(tok, Severity::performance, "stlcstrReturn", "Returning the result of c_str() in a function that returns std::string is slow and redundant.\n"
                 "The conversion from const char* as returned by c_str() to std::string creates an unnecessary string copy. Solve that by directly returning the string.", CWE704, Certainty::normal);
 }
 
-void CheckStl::string_c_strParam(const Token* tok, nonneg int number, const std::string& argtype)
+void CheckStlImpl::string_c_strParam(const Token* tok, nonneg int number, const std::string& argtype)
 {
     std::ostringstream oss;
     oss << "Passing the result of c_str() to a function that takes " << argtype << " as argument no. " << number << " is slow and redundant.\n"
@@ -2246,28 +2246,28 @@ void CheckStl::string_c_strParam(const Token* tok, nonneg int number, const std:
     reportError(tok, Severity::performance, "stlcstrParam", oss.str(), CWE704, Certainty::normal);
 }
 
-void CheckStl::string_c_strConstructor(const Token* tok, const std::string& argtype)
+void CheckStlImpl::string_c_strConstructor(const Token* tok, const std::string& argtype)
 {
     std::string msg = "Constructing a " + argtype + " from the result of c_str() is slow and redundant.\n"
                       "Constructing a " + argtype + " from const char* requires a call to strlen(). Solve that by directly passing the string.";
     reportError(tok, Severity::performance, "stlcstrConstructor", msg, CWE704, Certainty::normal);
 }
 
-void CheckStl::string_c_strAssignment(const Token* tok, const std::string& argtype)
+void CheckStlImpl::string_c_strAssignment(const Token* tok, const std::string& argtype)
 {
     std::string msg = "Assigning the result of c_str() to a " + argtype + " is slow and redundant.\n"
                       "Assigning a const char* to a " + argtype + " requires a call to strlen(). Solve that by directly assigning the string.";
     reportError(tok, Severity::performance, "stlcstrAssignment", msg, CWE704, Certainty::normal);
 }
 
-void CheckStl::string_c_strConcat(const Token* tok)
+void CheckStlImpl::string_c_strConcat(const Token* tok)
 {
     std::string msg = "Concatenating the result of c_str() and a std::string is slow and redundant.\n"
                       "Concatenating a const char* with a std::string requires a call to strlen(). Solve that by directly concatenating the strings.";
     reportError(tok, Severity::performance, "stlcstrConcat", msg, CWE704, Certainty::normal);
 }
 
-void CheckStl::string_c_strStream(const Token* tok)
+void CheckStlImpl::string_c_strStream(const Token* tok)
 {
     std::string msg = "Passing the result of c_str() to a stream is slow and redundant.\n"
                       "Passing a const char* to a stream requires a call to strlen(). Solve that by directly passing the string.";
@@ -2288,7 +2288,7 @@ namespace {
 
 }
 
-void CheckStl::uselessCalls()
+void CheckStlImpl::uselessCalls()
 {
     const bool printPerformance = mSettings->severity.isEnabled(Severity::performance);
     const bool printWarning = mSettings->severity.isEnabled(Severity::warning);
@@ -2349,7 +2349,7 @@ void CheckStl::uselessCalls()
 }
 
 
-void CheckStl::uselessCallsReturnValueError(const Token *tok, const std::string &varname, const std::string &function)
+void CheckStlImpl::uselessCallsReturnValueError(const Token *tok, const std::string &varname, const std::string &function)
 {
     std::ostringstream errmsg;
     errmsg << "$symbol:" << varname << '\n';
@@ -2362,7 +2362,7 @@ void CheckStl::uselessCallsReturnValueError(const Token *tok, const std::string
     reportError(tok, Severity::warning, "uselessCallsCompare", errmsg.str(), CWE628, Certainty::normal);
 }
 
-void CheckStl::uselessCallsSwapError(const Token *tok, const std::string &varname)
+void CheckStlImpl::uselessCallsSwapError(const Token *tok, const std::string &varname)
 {
     reportError(tok, Severity::performance, "uselessCallsSwap",
                 "$symbol:" + varname + "\n"
@@ -2372,7 +2372,7 @@ void CheckStl::uselessCallsSwapError(const Token *tok, const std::string &varnam
                 "code is inefficient. Is the object or the parameter wrong here?", CWE628, Certainty::normal);
 }
 
-void CheckStl::uselessCallsSubstrError(const Token *tok, SubstrErrorType type)
+void CheckStlImpl::uselessCallsSubstrError(const Token *tok, SubstrErrorType type)
 {
     std::string msg = "Ineffective call of function 'substr' because ";
     switch (type) {
@@ -2392,19 +2392,19 @@ void CheckStl::uselessCallsSubstrError(const Token *tok, SubstrErrorType type)
     reportError(tok, Severity::performance, "uselessCallsSubstr", msg, CWE398, Certainty::normal);
 }
 
-void CheckStl::uselessCallsConstructorError(const Token *tok)
+void CheckStlImpl::uselessCallsConstructorError(const Token *tok)
 {
     const std::string container = tok ? tok->str() : "";
     const std::string msg = "Inefficient constructor call: container '" + container + "' is assigned a partial copy of itself. Use erase() or resize() instead.";
     reportError(tok, Severity::performance, "uselessCallsConstructor", msg, CWE398, Certainty::normal);
 }
 
-void CheckStl::uselessCallsEmptyError(const Token *tok)
+void CheckStlImpl::uselessCallsEmptyError(const Token *tok)
 {
     reportError(tok, Severity::warning, "uselessCallsEmpty", "Ineffective call of function 'empty()'. Did you intend to call 'clear()' instead?", CWE398, Certainty::normal);
 }
 
-void CheckStl::uselessCallsRemoveError(const Token *tok, const std::string& function)
+void CheckStlImpl::uselessCallsRemoveError(const Token *tok, const std::string& function)
 {
     reportError(tok, Severity::warning, "uselessCallsRemove",
                 "$symbol:" + function + "\n"
@@ -2415,7 +2415,7 @@ void CheckStl::uselessCallsRemoveError(const Token *tok, const std::string& func
 
 // Check for iterators being dereferenced before being checked for validity.
 // E.g.  if (*i && i != str.end()) { }
-void CheckStl::checkDereferenceInvalidIterator()
+void CheckStlImpl::checkDereferenceInvalidIterator()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -2479,7 +2479,7 @@ void CheckStl::checkDereferenceInvalidIterator()
 }
 
 
-void CheckStl::checkDereferenceInvalidIterator2()
+void CheckStlImpl::checkDereferenceInvalidIterator2()
 {
     const bool printInconclusive = (mSettings->certainty.isEnabled(Certainty::inconclusive));
 
@@ -2575,7 +2575,7 @@ void CheckStl::checkDereferenceInvalidIterator2()
     }
 }
 
-void CheckStl::dereferenceInvalidIteratorError(const Token* tok, const ValueFlow::Value *value, bool inconclusive)
+void CheckStlImpl::dereferenceInvalidIteratorError(const Token* tok, const ValueFlow::Value *value, bool inconclusive)
 {
     const std::string& varname = tok ? tok->expressionString() : "var";
     const std::string errmsgcond("$symbol:" + varname + '\n' + ValueFlow::eitherTheConditionIsRedundant(value ? value->condition : nullptr) + " or there is possible dereference of an invalid iterator: $symbol.");
@@ -2604,7 +2604,7 @@ void CheckStl::dereferenceInvalidIteratorError(const Token* tok, const ValueFlow
     }
 }
 
-void CheckStl::dereferenceInvalidIteratorError(const Token* deref, const std::string &iterName)
+void CheckStlImpl::dereferenceInvalidIteratorError(const Token* deref, const std::string &iterName)
 {
     reportError(deref, Severity::warning,
                 "derefInvalidIterator",
@@ -2613,7 +2613,7 @@ void CheckStl::dereferenceInvalidIteratorError(const Token* deref, const std::st
                 "Possible dereference of an invalid iterator: $symbol. Make sure to check that the iterator is valid before dereferencing it - not after.", CWE825, Certainty::normal);
 }
 
-void CheckStl::useStlAlgorithmError(const Token *tok, const std::string &algoName)
+void CheckStlImpl::useStlAlgorithmError(const Token *tok, const std::string &algoName)
 {
     reportError(tok, Severity::style, "useStlAlgorithm",
                 "Consider using " + algoName + " algorithm instead of a raw loop.", CWE398, Certainty::normal);
@@ -3001,7 +3001,7 @@ namespace {
     };
 } // namespace
 
-void CheckStl::useStlAlgorithm()
+void CheckStlImpl::useStlAlgorithm()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("useStlAlgorithm"))
         return;
@@ -3237,7 +3237,7 @@ void CheckStl::useStlAlgorithm()
     }
 }
 
-void CheckStl::knownEmptyContainerError(const Token *tok, const std::string& algo)
+void CheckStlImpl::knownEmptyContainerError(const Token *tok, const std::string& algo)
 {
     const std::string var = tok ? tok->expressionString() : std::string("var");
 
@@ -3268,7 +3268,7 @@ static bool isKnownEmptyContainer(const Token* tok)
     });
 }
 
-void CheckStl::knownEmptyContainer()
+void CheckStlImpl::knownEmptyContainer()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("knownEmptyContainer"))
         return;
@@ -3311,7 +3311,7 @@ void CheckStl::knownEmptyContainer()
     }
 }
 
-void CheckStl::eraseIteratorOutOfBoundsError(const Token *ftok, const Token* itertok, const ValueFlow::Value* val)
+void CheckStlImpl::eraseIteratorOutOfBoundsError(const Token *ftok, const Token* itertok, const ValueFlow::Value* val)
 {
     if (!ftok || !itertok || !val) {
         reportError(ftok, Severity::error, "eraseIteratorOutOfBounds",
@@ -3356,7 +3356,7 @@ static const ValueFlow::Value* getOOBIterValue(const Token* tok, const ValueFlow
     return it != tok->values().end() ? &*it : nullptr;
 }
 
-void CheckStl::eraseIteratorOutOfBounds()
+void CheckStlImpl::eraseIteratorOutOfBounds()
 {
     logChecker("CheckStl::eraseIteratorOutOfBounds");
     for (const Scope *function : mTokenizer->getSymbolDatabase()->functionScopes) {
@@ -3403,21 +3403,21 @@ static bool isLocalMutex(const Variable* var, const Scope* scope)
     return !var->isReference() && !var->isRValueReference() && !var->isStatic() && var->scope() == scope;
 }
 
-void CheckStl::globalLockGuardError(const Token* tok)
+void CheckStlImpl::globalLockGuardError(const Token* tok)
 {
     reportError(tok, Severity::warning,
                 "globalLockGuard",
                 "Lock guard is defined globally. Lock guards are intended to be local. A global lock guard could lead to a deadlock since it won't unlock until the end of the program.", CWE833, Certainty::normal);
 }
 
-void CheckStl::localMutexError(const Token* tok)
+void CheckStlImpl::localMutexError(const Token* tok)
 {
     reportError(tok, Severity::warning,
                 "localMutex",
                 "The lock is ineffective because the mutex is locked at the same scope as the mutex itself.", CWE667, Certainty::normal);
 }
 
-void CheckStl::checkMutexes()
+void CheckStlImpl::checkMutexes()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -3460,7 +3460,7 @@ void CheckStl::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
         return;
     }
 
-    CheckStl checkStl(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckStlImpl checkStl(&tokenizer, &tokenizer.getSettings(), errorLogger);
     checkStl.erase();
     checkStl.if_find();
     checkStl.checkFindInsert();
@@ -3493,7 +3493,7 @@ void CheckStl::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 
 void CheckStl::getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const
 {
-    CheckStl c(nullptr, settings, errorLogger);
+    CheckStlImpl c(nullptr, settings, errorLogger);
     c.outOfBoundsError(nullptr, "container", nullptr, "x", nullptr);
     c.invalidIteratorError(nullptr, "iterator");
     c.iteratorsError(nullptr, "container1", "container2");
@@ -3525,7 +3525,7 @@ void CheckStl::getErrorMessages(ErrorLogger* errorLogger, const Settings* settin
     c.redundantIfRemoveError(nullptr);
     c.uselessCallsReturnValueError(nullptr, "str", "find");
     c.uselessCallsSwapError(nullptr, "str");
-    c.uselessCallsSubstrError(nullptr, SubstrErrorType::COPY);
+    c.uselessCallsSubstrError(nullptr, CheckStlImpl::SubstrErrorType::COPY);
     c.uselessCallsConstructorError(nullptr);
     c.uselessCallsEmptyError(nullptr);
     c.uselessCallsRemoveError(nullptr, "remove");
diff --git a/lib/checkstl.h b/lib/checkstl.h
index 03a634f1ed1..626e39f4276 100644
--- a/lib/checkstl.h
+++ b/lib/checkstl.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 #include "errortypes.h"
 
@@ -48,16 +49,43 @@ namespace ValueFlow
 class CPPCHECKLIB CheckStl : public Check {
 public:
     /** This constructor is used when registering the CheckClass */
-    CheckStl() : Check(myName()) {}
+    CheckStl() : Check("STL usage") {}
 
 private:
-    /** This constructor is used when running checks. */
-    CheckStl(const Tokenizer* tokenizer, const Settings* settings, ErrorLogger* errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     /** run checks, the token list is not simplified */
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
+    void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const override;
+
+    std::string classInfo() const override {
+        return "Check for invalid usage of STL:\n"
+               "- out of bounds errors\n"
+               "- misuse of iterators when iterating through a container\n"
+               "- mismatching containers in calls\n"
+               "- same iterators in calls\n"
+               "- dereferencing an erased iterator\n"
+               "- for vectors: using iterator/pointer after push_back has been used\n"
+               "- optimisation: use empty() instead of size() to guarantee fast code\n"
+               "- suspicious condition when using find\n"
+               "- unnecessary searching in associative containers\n"
+               "- redundant condition\n"
+               "- common mistakes when using string::c_str()\n"
+               "- useless calls of string and STL functions\n"
+               "- dereferencing an invalid iterator\n"
+               "- erasing an iterator that is out of bounds\n"
+               "- reading from empty STL container\n"
+               "- iterating over an empty STL container\n"
+               "- consider using an STL algorithm instead of raw loop\n"
+               "- incorrect locking with mutex\n";
+    }
+};
+
+class CPPCHECKLIB CheckStlImpl : public CheckImpl {
+public:
+    /** This constructor is used when running checks. */
+    CheckStlImpl(const Tokenizer* tokenizer, const Settings* settings, ErrorLogger* errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     /** Accessing container out of bounds using ValueFlow */
     void outOfBounds();
 
@@ -209,34 +237,6 @@ class CPPCHECKLIB CheckStl : public Check {
 
     void globalLockGuardError(const Token *tok);
     void localMutexError(const Token *tok);
-
-    void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const override;
-
-    static std::string myName() {
-        return "STL usage";
-    }
-
-    std::string classInfo() const override {
-        return "Check for invalid usage of STL:\n"
-               "- out of bounds errors\n"
-               "- misuse of iterators when iterating through a container\n"
-               "- mismatching containers in calls\n"
-               "- same iterators in calls\n"
-               "- dereferencing an erased iterator\n"
-               "- for vectors: using iterator/pointer after push_back has been used\n"
-               "- optimisation: use empty() instead of size() to guarantee fast code\n"
-               "- suspicious condition when using find\n"
-               "- unnecessary searching in associative containers\n"
-               "- redundant condition\n"
-               "- common mistakes when using string::c_str()\n"
-               "- useless calls of string and STL functions\n"
-               "- dereferencing an invalid iterator\n"
-               "- erasing an iterator that is out of bounds\n"
-               "- reading from empty STL container\n"
-               "- iterating over an empty STL container\n"
-               "- consider using an STL algorithm instead of raw loop\n"
-               "- incorrect locking with mutex\n";
-    }
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checkstring.cpp b/lib/checkstring.cpp
index 580597bb10d..916885e094a 100644
--- a/lib/checkstring.cpp
+++ b/lib/checkstring.cpp
@@ -47,7 +47,7 @@ static const CWE CWE758(758U);   // Reliance on Undefined, Unspecified, or Imple
 //---------------------------------------------------------------------------
 // Writing string literal is UB
 //---------------------------------------------------------------------------
-void CheckString::stringLiteralWrite()
+void CheckStringImpl::stringLiteralWrite()
 {
     logChecker("CheckString::stringLiteralWrite");
     const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -66,7 +66,7 @@ void CheckString::stringLiteralWrite()
     }
 }
 
-void CheckString::stringLiteralWriteError(const Token *tok, const Token *strValue)
+void CheckStringImpl::stringLiteralWriteError(const Token *tok, const Token *strValue)
 {
     std::list<const Token*> callstack{ tok };
     if (strValue)
@@ -89,7 +89,7 @@ void CheckString::stringLiteralWriteError(const Token *tok, const Token *strValu
 // Check for string comparison involving two static strings.
 // if(strcmp("00FF00","00FF00")==0) // <- statement is always true
 //---------------------------------------------------------------------------
-void CheckString::checkAlwaysTrueOrFalseStringCompare()
+void CheckStringImpl::checkAlwaysTrueOrFalseStringCompare()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -133,7 +133,7 @@ void CheckString::checkAlwaysTrueOrFalseStringCompare()
     }
 }
 
-void CheckString::alwaysTrueFalseStringCompareError(const Token *tok, const std::string& str1, const std::string& str2)
+void CheckStringImpl::alwaysTrueFalseStringCompareError(const Token *tok, const std::string& str1, const std::string& str2)
 {
     constexpr std::size_t stringLen = 10;
     const std::string string1 = (str1.size() < stringLen) ? str1 : (str1.substr(0, stringLen-2) + "..");
@@ -145,7 +145,7 @@ void CheckString::alwaysTrueFalseStringCompareError(const Token *tok, const std:
                 "Therefore the comparison is unnecessary and looks suspicious.", (str1==str2)?CWE571:CWE570, Certainty::normal);
 }
 
-void CheckString::alwaysTrueStringVariableCompareError(const Token *tok, const std::string& str1, const std::string& str2)
+void CheckStringImpl::alwaysTrueStringVariableCompareError(const Token *tok, const std::string& str1, const std::string& str2)
 {
     reportError(tok, Severity::warning, "stringCompare",
                 "Comparison of identical string variables.\n"
@@ -158,7 +158,7 @@ void CheckString::alwaysTrueStringVariableCompareError(const Token *tok, const s
 // Detect "str == '\0'" where "*str == '\0'" is correct.
 // Comparing char* with each other instead of using strcmp()
 //-----------------------------------------------------------------------------
-void CheckString::checkSuspiciousStringCompare()
+void CheckStringImpl::checkSuspiciousStringCompare()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -197,14 +197,14 @@ void CheckString::checkSuspiciousStringCompare()
     }
 }
 
-void CheckString::suspiciousStringCompareError(const Token* tok, const std::string& var, bool isLong)
+void CheckStringImpl::suspiciousStringCompareError(const Token* tok, const std::string& var, bool isLong)
 {
     const std::string cmpFunc = isLong ? "wcscmp" : "strcmp";
     reportError(tok, Severity::warning, "literalWithCharPtrCompare",
                 "$symbol:" + var + "\nString literal compared with variable '$symbol'. Did you intend to use " + cmpFunc + "() instead?", CWE595, Certainty::normal);
 }
 
-void CheckString::suspiciousStringCompareError_char(const Token* tok, const std::string& var)
+void CheckStringImpl::suspiciousStringCompareError_char(const Token* tok, const std::string& var)
 {
     reportError(tok, Severity::warning, "charLiteralWithCharPtrCompare",
                 "$symbol:" + var + "\nChar literal compared with pointer '$symbol'. Did you intend to dereference it?", CWE595, Certainty::normal);
@@ -220,7 +220,7 @@ static bool isChar(const Variable* var)
     return (var && !var->isPointer() && !var->isArray() && (var->typeStartToken()->str() == "char" || var->typeStartToken()->str() == "wchar_t"));
 }
 
-void CheckString::strPlusChar()
+void CheckStringImpl::strPlusChar()
 {
     logChecker("CheckString::strPlusChar");
     const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -236,7 +236,7 @@ void CheckString::strPlusChar()
     }
 }
 
-void CheckString::strPlusCharError(const Token *tok)
+void CheckStringImpl::strPlusCharError(const Token *tok)
 {
     std::string charType = "char";
     if (tok && tok->astOperand2() && tok->astOperand2()->variable())
@@ -272,7 +272,7 @@ static bool isMacroUsage(const Token* tok)
 // Implicit casts of string literals to bool
 // Comparing string literal with strlen() with wrong length
 //---------------------------------------------------------------------------
-void CheckString::checkIncorrectStringCompare()
+void CheckStringImpl::checkIncorrectStringCompare()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -321,12 +321,12 @@ void CheckString::checkIncorrectStringCompare()
     }
 }
 
-void CheckString::incorrectStringCompareError(const Token *tok, const std::string& func, const std::string &string)
+void CheckStringImpl::incorrectStringCompareError(const Token *tok, const std::string& func, const std::string &string)
 {
     reportError(tok, Severity::warning, "incorrectStringCompare", "$symbol:" + func + "\nString literal " + string + " doesn't match length argument for $symbol().", CWE570, Certainty::normal);
 }
 
-void CheckString::incorrectStringBooleanError(const Token *tok, const std::string& string)
+void CheckStringImpl::incorrectStringBooleanError(const Token *tok, const std::string& string)
 {
     const bool charLiteral = isCharLiteral(string);
     const std::string literalType = charLiteral ? "char" : "string";
@@ -341,7 +341,7 @@ void CheckString::incorrectStringBooleanError(const Token *tok, const std::strin
 // always true: strcmp(str,"a")==0 || strcmp(str,"b")
 // TODO: Library configuration for string comparison functions
 //---------------------------------------------------------------------------
-void CheckString::overlappingStrcmp()
+void CheckStringImpl::overlappingStrcmp()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -403,7 +403,7 @@ void CheckString::overlappingStrcmp()
     }
 }
 
-void CheckString::overlappingStrcmpError(const Token *eq0, const Token *ne0)
+void CheckStringImpl::overlappingStrcmpError(const Token *eq0, const Token *ne0)
 {
     std::string eq0Expr(eq0 ? eq0->expressionString() : std::string("strcmp(x,\"abc\")"));
     if (eq0 && eq0->astParent()->str() == "!")
@@ -420,7 +420,7 @@ void CheckString::overlappingStrcmpError(const Token *eq0, const Token *ne0)
 // Overlapping source and destination passed to sprintf().
 // TODO: Library configuration for overlapping arguments
 //---------------------------------------------------------------------------
-void CheckString::sprintfOverlappingData()
+void CheckStringImpl::sprintfOverlappingData()
 {
     logChecker("CheckString::sprintfOverlappingData");
 
@@ -457,7 +457,7 @@ void CheckString::sprintfOverlappingData()
     }
 }
 
-void CheckString::sprintfOverlappingDataError(const Token *funcTok, const Token *tok, const std::string &varname)
+void CheckStringImpl::sprintfOverlappingDataError(const Token *funcTok, const Token *tok, const std::string &varname)
 {
     const std::string func = funcTok ? funcTok->str() : "s[n]printf";
 
@@ -473,7 +473,7 @@ void CheckString::sprintfOverlappingDataError(const Token *funcTok, const Token
 
 void CheckString::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    CheckString checkString(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckStringImpl checkString(&tokenizer, &tokenizer.getSettings(), errorLogger);
 
     // Checks
     checkString.strPlusChar();
@@ -487,7 +487,7 @@ void CheckString::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger
 
 void CheckString::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckString c(nullptr, settings, errorLogger);
+    CheckStringImpl c(nullptr, settings, errorLogger);
     c.stringLiteralWriteError(nullptr, nullptr);
     c.sprintfOverlappingDataError(nullptr, nullptr, "varname");
     c.strPlusCharError(nullptr);
diff --git a/lib/checkstring.h b/lib/checkstring.h
index 76002f8ed3d..9edefc3f8b0 100644
--- a/lib/checkstring.h
+++ b/lib/checkstring.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <string>
@@ -41,16 +42,32 @@ class Tokenizer;
 class CPPCHECKLIB CheckString : public Check {
 public:
     /** @brief This constructor is used when registering the CheckClass */
-    CheckString() : Check(myName()) {}
+    CheckString() : Check("String") {}
 
 private:
-    /** @brief This constructor is used when running checks. */
-    CheckString(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     /** @brief Run checks against the normal token list */
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+
+    std::string classInfo() const override {
+        return "Detect misusage of C-style strings:\n"
+               "- overlapping buffers passed to sprintf as source and destination\n"
+               "- incorrect length arguments for 'substr' and 'strncmp'\n"
+               "- suspicious condition (runtime comparison of string literals)\n"
+               "- suspicious condition (string/char literals as boolean)\n"
+               "- suspicious comparison of a string literal with a char\\* variable\n"
+               "- suspicious comparison of '\\0' with a char\\* variable\n"
+               "- overlapping strcmp() expression\n";
+    }
+};
+
+class CPPCHECKLIB CheckStringImpl : public CheckImpl {
+public:
+    /** @brief This constructor is used when running checks. */
+    CheckStringImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     /** @brief undefined behaviour, writing string literal */
     void stringLiteralWrite();
 
@@ -82,23 +99,6 @@ class CPPCHECKLIB CheckString : public Check {
     void suspiciousStringCompareError(const Token* tok, const std::string& var, bool isLong);
     void suspiciousStringCompareError_char(const Token* tok, const std::string& var);
     void overlappingStrcmpError(const Token* eq0, const Token *ne0);
-
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "String";
-    }
-
-    std::string classInfo() const override {
-        return "Detect misusage of C-style strings:\n"
-               "- overlapping buffers passed to sprintf as source and destination\n"
-               "- incorrect length arguments for 'substr' and 'strncmp'\n"
-               "- suspicious condition (runtime comparison of string literals)\n"
-               "- suspicious condition (string/char literals as boolean)\n"
-               "- suspicious comparison of a string literal with a char\\* variable\n"
-               "- suspicious comparison of '\\0' with a char\\* variable\n"
-               "- overlapping strcmp() expression\n";
-    }
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checktype.cpp b/lib/checktype.cpp
index eb222fbe6f5..1679d98e80f 100644
--- a/lib/checktype.cpp
+++ b/lib/checktype.cpp
@@ -56,7 +56,7 @@ static const CWE CWE758(758U);   // Reliance on Undefined, Unspecified, or Imple
 static const CWE CWE190(190U);   // Integer Overflow or Wraparound
 
 
-void CheckType::checkTooBigBitwiseShift()
+void CheckTypeImpl::checkTooBigBitwiseShift()
 {
     // unknown sizeof(int) => can't run this checker
     if (mSettings->platform.type == Platform::Type::Unspecified)
@@ -110,7 +110,7 @@ void CheckType::checkTooBigBitwiseShift()
     }
 }
 
-void CheckType::tooBigBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits)
+void CheckTypeImpl::tooBigBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits)
 {
     constexpr char id[] = "shiftTooManyBits";
 
@@ -129,7 +129,7 @@ void CheckType::tooBigBitwiseShiftError(const Token *tok, int lhsbits, const Val
     reportError(std::move(errorPath), rhsbits.errorSeverity() ? Severity::error : Severity::warning, id, errmsg.str(), CWE758, rhsbits.isInconclusive() ? Certainty::inconclusive : Certainty::normal);
 }
 
-void CheckType::tooBigSignedBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits)
+void CheckTypeImpl::tooBigSignedBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits)
 {
     constexpr char id[] = "shiftTooManyBitsSigned";
 
@@ -164,7 +164,7 @@ void CheckType::tooBigSignedBitwiseShiftError(const Token *tok, int lhsbits, con
 // Checking for integer overflow
 //---------------------------------------------------------------------------
 
-void CheckType::checkIntegerOverflow()
+void CheckTypeImpl::checkIntegerOverflow()
 {
     // unknown sizeof(int) => can't run this checker
     if (mSettings->platform.type == Platform::Type::Unspecified || mSettings->platform.int_bit >= MathLib::bigint_bits)
@@ -215,7 +215,16 @@ void CheckType::checkIntegerOverflow()
     }
 }
 
-void CheckType::integerOverflowError(const Token *tok, const ValueFlow::Value &value, bool isOverflow)
+static std::string getMessageId(const ValueFlow::Value &value, const char id[])
+{
+    if (value.condition != nullptr)
+        return id + std::string("Cond");
+    if (value.safe)
+        return std::string("safe") + static_cast<char>(std::toupper(id[0])) + (id + 1);
+    return id;
+}
+
+void CheckTypeImpl::integerOverflowError(const Token *tok, const ValueFlow::Value &value, bool isOverflow)
 {
     const std::string expr(tok ? tok->expressionString() : "");
     const std::string type = isOverflow ? "overflow" : "underflow";
@@ -242,7 +251,7 @@ void CheckType::integerOverflowError(const Token *tok, const ValueFlow::Value &v
 // Checking for sign conversion when operand can be negative
 //---------------------------------------------------------------------------
 
-void CheckType::checkSignConversion()
+void CheckTypeImpl::checkSignConversion()
 {
     if (!mSettings->severity.isEnabled(Severity::warning))
         return;
@@ -274,7 +283,7 @@ void CheckType::checkSignConversion()
     }
 }
 
-void CheckType::signConversionError(const Token *tok, const ValueFlow::Value *negativeValue, const bool constvalue)
+void CheckTypeImpl::signConversionError(const Token *tok, const ValueFlow::Value *negativeValue, const bool constvalue)
 {
     const std::string expr(tok ? tok->expressionString() : "var");
 
@@ -292,7 +301,7 @@ void CheckType::signConversionError(const Token *tok, const ValueFlow::Value *ne
         ErrorPath errorPath = getErrorPath(tok,negativeValue,"Negative value is converted to an unsigned value");
         reportError(std::move(errorPath),
                     Severity::warning,
-                    Check::getMessageId(*negativeValue, "signConversion").c_str(),
+                    getMessageId(*negativeValue, "signConversion").c_str(),
                     msg.str(),
                     CWE195,
                     negativeValue->isInconclusive() ? Certainty::inconclusive : Certainty::normal);
@@ -327,7 +336,7 @@ static bool checkTypeCombination(ValueType src, ValueType tgt, const Settings& s
     });
 }
 
-void CheckType::checkLongCast()
+void CheckTypeImpl::checkLongCast()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("truncLongCastAssignment"))
         return;
@@ -405,7 +414,7 @@ static void makeBaseTypeString(std::string& typeStr)
         typeStr.erase(typeStr.begin(), typeStr.begin() + pos + 6 + 1);
 }
 
-void CheckType::longCastAssignError(const Token *tok, const ValueType* src, const ValueType* tgt)
+void CheckTypeImpl::longCastAssignError(const Token *tok, const ValueType* src, const ValueType* tgt)
 {
     std::string srcStr = src ? src->str() : "int";
     makeBaseTypeString(srcStr);
@@ -418,7 +427,7 @@ void CheckType::longCastAssignError(const Token *tok, const ValueType* src, cons
                 srcStr + " result is assigned to " + tgtStr + " variable. If the variable is " + tgtStr + " to avoid loss of information, then there is loss of information. To avoid loss of information you must cast a calculation operand to " + tgtStr + ", for example 'l = a * b;' => 'l = (" + tgtStr + ")a * b;'.", CWE197, Certainty::normal);
 }
 
-void CheckType::longCastReturnError(const Token *tok, const ValueType* src, const ValueType* tgt)
+void CheckTypeImpl::longCastReturnError(const Token *tok, const ValueType* src, const ValueType* tgt)
 {
     std::string srcStr = src ? src->str() : "int";
     makeBaseTypeString(srcStr);
@@ -435,7 +444,7 @@ void CheckType::longCastReturnError(const Token *tok, const ValueType* src, cons
 // Checking for float to integer overflow
 //---------------------------------------------------------------------------
 
-void CheckType::checkFloatToIntegerOverflow()
+void CheckTypeImpl::checkFloatToIntegerOverflow()
 {
     logChecker("CheckType::checkFloatToIntegerOverflow");
 
@@ -475,7 +484,7 @@ void CheckType::checkFloatToIntegerOverflow()
     }
 }
 
-void CheckType::checkFloatToIntegerOverflow(const Token *tok, const ValueType *vtint, const ValueType *vtfloat, const std::list<ValueFlow::Value> &floatValues)
+void CheckTypeImpl::checkFloatToIntegerOverflow(const Token *tok, const ValueType *vtint, const ValueType *vtfloat, const std::list<ValueFlow::Value> &floatValues)
 {
     // Conversion of float to integer?
     if (!vtint || !vtint->isIntegral())
@@ -512,7 +521,7 @@ void CheckType::checkFloatToIntegerOverflow(const Token *tok, const ValueType *v
     }
 }
 
-void CheckType::floatToIntegerOverflowError(const Token *tok, const ValueFlow::Value &value)
+void CheckTypeImpl::floatToIntegerOverflowError(const Token *tok, const ValueFlow::Value &value)
 {
     std::ostringstream errmsg;
     errmsg << "Undefined behaviour: float (" << value.floatValue << ") to integer conversion overflow.";
@@ -525,7 +534,7 @@ void CheckType::floatToIntegerOverflowError(const Token *tok, const ValueFlow::V
 void CheckType::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
     // These are not "simplified" because casts can't be ignored
-    CheckType checkType(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckTypeImpl checkType(&tokenizer, &tokenizer.getSettings(), errorLogger);
     checkType.checkTooBigBitwiseShift();
     checkType.checkIntegerOverflow();
     checkType.checkSignConversion();
@@ -535,7 +544,7 @@ void CheckType::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 
 void CheckType::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckType c(nullptr, settings, errorLogger);
+    CheckTypeImpl c(nullptr, settings, errorLogger);
     c.tooBigBitwiseShiftError(nullptr, 32, ValueFlow::Value(64));
     c.tooBigSignedBitwiseShiftError(nullptr, 31, ValueFlow::Value(31));
     c.integerOverflowError(nullptr, ValueFlow::Value(1LL<<32));
diff --git a/lib/checktype.h b/lib/checktype.h
index d90e11f6fd1..a65ed7ea084 100644
--- a/lib/checktype.h
+++ b/lib/checktype.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <list>
@@ -47,16 +48,31 @@ namespace ValueFlow
 class CPPCHECKLIB CheckType : public Check {
 public:
     /** @brief This constructor is used when registering the CheckClass */
-    CheckType() : Check(myName()) {}
+    CheckType() : Check("Type") {}
 
 private:
-    /** @brief This constructor is used when running checks. */
-    CheckType(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     /** @brief Run checks against the normal token list */
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+
+    std::string classInfo() const override {
+        return "Type checks\n"
+               "- bitwise shift by too many bits (only enabled when --platform is used)\n"
+               "- signed integer overflow (only enabled when --platform is used)\n"
+               "- dangerous sign conversion, when signed value can be negative\n"
+               "- possible loss of information when assigning int result to long variable\n"
+               "- possible loss of information when returning int result as long return value\n"
+               "- float conversion overflow\n";
+    }
+};
+
+class CPPCHECKLIB CheckTypeImpl : public CheckImpl {
+public:
+    /** @brief This constructor is used when running checks. */
+    CheckTypeImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     /** @brief %Check for bitwise shift with too big right operand */
     void checkTooBigBitwiseShift();
 
@@ -81,22 +97,6 @@ class CPPCHECKLIB CheckType : public Check {
     void longCastAssignError(const Token *tok, const ValueType* src = nullptr, const ValueType* tgt = nullptr);
     void longCastReturnError(const Token *tok, const ValueType* src = nullptr, const ValueType* tgt = nullptr);
     void floatToIntegerOverflowError(const Token *tok, const ValueFlow::Value &value);
-
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "Type";
-    }
-
-    std::string classInfo() const override {
-        return "Type checks\n"
-               "- bitwise shift by too many bits (only enabled when --platform is used)\n"
-               "- signed integer overflow (only enabled when --platform is used)\n"
-               "- dangerous sign conversion, when signed value can be negative\n"
-               "- possible loss of information when assigning int result to long variable\n"
-               "- possible loss of information when returning int result as long return value\n"
-               "- float conversion overflow\n";
-    }
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp
index b88debda6f8..f1d71a92f35 100644
--- a/lib/checkuninitvar.cpp
+++ b/lib/checkuninitvar.cpp
@@ -21,6 +21,7 @@
 #include "checkuninitvar.h"
 
 #include "astutils.h"
+#include "checkimpl.h"
 #include "ctu.h"
 #include "errorlogger.h"
 #include "library.h"
@@ -97,7 +98,7 @@ static std::map<nonneg int, VariableValue> getVariableValues(const Token* tok) {
     return ret;
 }
 
-bool CheckUninitVar::diag(const Token* tok)
+bool CheckUninitVarImpl::diag(const Token* tok)
 {
     if (!tok)
         return true;
@@ -106,7 +107,7 @@ bool CheckUninitVar::diag(const Token* tok)
     return !mUninitDiags.insert(tok).second;
 }
 
-void CheckUninitVar::check()
+void CheckUninitVarImpl::check()
 {
     logChecker("CheckUninitVar::check");
 
@@ -126,7 +127,7 @@ void CheckUninitVar::check()
     }
 }
 
-void CheckUninitVar::checkScope(const Scope* scope, const std::set<std::string> &arrayTypeDefs)
+void CheckUninitVarImpl::checkScope(const Scope* scope, const std::set<std::string> &arrayTypeDefs)
 {
     for (const Variable &var : scope->varlist) {
         if ((mTokenizer->isCPP() && var.type() && !var.isPointer() && var.type()->needInitialization != Type::NeedInitialization::True) ||
@@ -231,7 +232,7 @@ void CheckUninitVar::checkScope(const Scope* scope, const std::set<std::string>
     }
 }
 
-void CheckUninitVar::checkStruct(const Token *tok, const Variable &structvar)
+void CheckUninitVarImpl::checkStruct(const Token *tok, const Variable &structvar)
 {
     const Token *typeToken = structvar.typeStartToken();
     while (Token::Match(typeToken, "%name% ::"))
@@ -392,7 +393,7 @@ static bool isVariableUsed(const Token *tok, const Variable& var)
     return !parent2 || parent2->isConstOp() || (parent2->str() == "=" && parent2->astOperand2() == parent);
 }
 
-bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var, bool * const possibleInit, bool * const noreturn, Alloc* const alloc, const std::string &membervar, std::map<nonneg int, VariableValue>& variableValue)
+bool CheckUninitVarImpl::checkScopeForVariable(const Token *tok, const Variable& var, bool * const possibleInit, bool * const noreturn, Alloc* const alloc, const std::string &membervar, std::map<nonneg int, VariableValue>& variableValue)
 {
     const bool suppressErrors(possibleInit && *possibleInit);  // Assume that this is a variable declaration, rather than a fundef
     const bool printDebug = mSettings->debugwarnings;
@@ -728,7 +729,7 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
                     }
 
                     // Use variable
-                    else if (!suppressErrors && isVariableUsage(tok, var.isPointer(), *alloc))
+                    else if (!suppressErrors && isVariableUsage(tok, mSettings->library, var.isPointer(), *alloc))
                         uninitvarError(tok, tok->str(), *alloc);
 
                     return true;
@@ -817,7 +818,7 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
 
             } else {
                 // Use variable
-                if (!suppressErrors && isVariableUsage(tok, var.isPointer(), *alloc)) {
+                if (!suppressErrors && isVariableUsage(tok, mSettings->library, var.isPointer(), *alloc)) {
                     uninitvarError(tok, tok->str(), *alloc);
                     return true;
                 }
@@ -852,7 +853,7 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
     return false;
 }
 
-const Token* CheckUninitVar::checkExpr(const Token* tok, const Variable& var, const Alloc alloc, bool known, bool* bailout) const
+const Token* CheckUninitVarImpl::checkExpr(const Token* tok, const Variable& var, const Alloc alloc, bool known, bool* bailout) const
 {
     if (!tok)
         return nullptr;
@@ -872,7 +873,7 @@ const Token* CheckUninitVar::checkExpr(const Token* tok, const Variable& var, co
     if (tok->astOperand2())
         return checkExpr(tok->astOperand2(), var, alloc, known, bailout);
     if (tok->varId() == var.declarationId()) {
-        const Token *errorToken = isVariableUsage(tok, var.isPointer(), alloc);
+        const Token *errorToken = isVariableUsage(tok, mSettings->library, var.isPointer(), alloc);
         if (errorToken)
             return errorToken;
         if (bailout)
@@ -881,7 +882,7 @@ const Token* CheckUninitVar::checkExpr(const Token* tok, const Variable& var, co
     return nullptr;
 }
 
-bool CheckUninitVar::checkIfForWhileHead(const Token *startparentheses, const Variable& var, bool suppressErrors, bool isuninit, Alloc alloc, const std::string &membervar)
+bool CheckUninitVarImpl::checkIfForWhileHead(const Token *startparentheses, const Variable& var, bool suppressErrors, bool isuninit, Alloc alloc, const std::string &membervar)
 {
     const Token * const endpar = startparentheses->link();
     if (Token::Match(startparentheses, "( ! %name% %oror%") && startparentheses->tokAt(2)->getValue(0))
@@ -901,7 +902,7 @@ bool CheckUninitVar::checkIfForWhileHead(const Token *startparentheses, const Va
                 continue;
             }
 
-            if (const Token *errorToken = isVariableUsage(tok, var.isPointer(), alloc)) {
+            if (const Token *errorToken = isVariableUsage(tok, mSettings->library, var.isPointer(), alloc)) {
                 if (suppressErrors)
                     continue;
                 uninitvarError(errorToken, errorToken->expressionString(), alloc);
@@ -918,7 +919,7 @@ bool CheckUninitVar::checkIfForWhileHead(const Token *startparentheses, const Va
 }
 
 /** recursively check loop, return error token */
-const Token* CheckUninitVar::checkLoopBodyRecursive(const Token *start, const Variable& var, const Alloc alloc, const std::string &membervar, bool &bailout, bool &alwaysReturns) const
+const Token* CheckUninitVarImpl::checkLoopBodyRecursive(const Token *start, const Variable& var, const Alloc alloc, const std::string &membervar, bool &bailout, bool &alwaysReturns) const
 {
     assert(start->str() == "{");
 
@@ -1054,7 +1055,7 @@ const Token* CheckUninitVar::checkLoopBodyRecursive(const Token *start, const Va
                 return nullptr;
             }
         } else {
-            if (const Token *errtok = isVariableUsage(tok, var.isPointer(), alloc)) {
+            if (const Token *errtok = isVariableUsage(tok, mSettings->library, var.isPointer(), alloc)) {
                 if (!conditionalUsage)
                     return errtok;
                 if (!errorToken)
@@ -1086,7 +1087,7 @@ const Token* CheckUninitVar::checkLoopBodyRecursive(const Token *start, const Va
     return errorToken;
 }
 
-bool CheckUninitVar::checkLoopBody(const Token *tok, const Variable& var, const Alloc alloc, const std::string &membervar, const bool suppressErrors)
+bool CheckUninitVarImpl::checkLoopBody(const Token *tok, const Variable& var, const Alloc alloc, const std::string &membervar, const bool suppressErrors)
 {
     bool bailout = false;
     bool alwaysReturns = false;
@@ -1103,7 +1104,7 @@ bool CheckUninitVar::checkLoopBody(const Token *tok, const Variable& var, const
     return bailout || alwaysReturns;
 }
 
-void CheckUninitVar::checkRhs(const Token *tok, const Variable &var, Alloc alloc, nonneg int number_of_if, const std::string &membervar)
+void CheckUninitVarImpl::checkRhs(const Token *tok, const Variable &var, Alloc alloc, nonneg int number_of_if, const std::string &membervar)
 {
     bool rhs = false;
     int indent = 0;
@@ -1111,7 +1112,7 @@ void CheckUninitVar::checkRhs(const Token *tok, const Variable &var, Alloc alloc
         if (tok->str() == "=")
             rhs = true;
         else if (rhs && tok->varId() == var.declarationId()) {
-            if (membervar.empty() && isVariableUsage(tok, var.isPointer(), alloc))
+            if (membervar.empty() && isVariableUsage(tok, mSettings->library, var.isPointer(), alloc))
                 uninitvarError(tok, tok->str(), alloc);
             else if (!membervar.empty() && isMemberVariableUsage(tok, var.isPointer(), alloc, membervar))
                 uninitStructMemberError(tok, tok->str() + "." + membervar);
@@ -1150,7 +1151,7 @@ static bool astIsRhs(const Token *tok)
     return tok && tok->astParent() && tok == tok->astParent()->astOperand2();
 }
 
-const Token* CheckUninitVar::isVariableUsage(const Token *vartok, const Library& library, bool pointer, Alloc alloc, int indirect)
+const Token* CheckUninitVarImpl::isVariableUsage(const Token *vartok, const Library& library, bool pointer, Alloc alloc, int indirect)
 {
     const bool cpp = vartok->isCpp();
     const Token *valueExpr = vartok;   // non-dereferenced , no address of value as variable
@@ -1257,17 +1258,17 @@ const Token* CheckUninitVar::isVariableUsage(const Token *vartok, const Library&
         const Token *parent = valueExpr->astParent();
         while (Token::simpleMatch(parent, ","))
             parent = parent->astParent();
-        const int use = isFunctionParUsage(valueExpr, library, pointer, alloc, indirect);
+        const int use = CheckUninitVarImpl::isFunctionParUsage(valueExpr, library, pointer, alloc, indirect);
         return (use>0) ? valueExpr : nullptr;
     }
     if (derefValue && Token::Match(derefValue->astParent(), "[(,]") && (derefValue->astParent()->str() == "," || astIsRhs(derefValue))) {
-        const int use = isFunctionParUsage(derefValue, library, false, NO_ALLOC, indirect);
+        const int use = CheckUninitVarImpl::isFunctionParUsage(derefValue, library, false, NO_ALLOC, indirect);
         return (use>0) ? derefValue : nullptr;
     }
     if (valueExpr->astParent()->isUnaryOp("&")) {
         const Token *parent = valueExpr->astParent();
         if (Token::Match(parent->astParent(), "[(,]") && (parent->astParent()->str() == "," || astIsRhs(parent))) {
-            const int use = isFunctionParUsage(valueExpr, library, pointer, alloc, indirect);
+            const int use = CheckUninitVarImpl::isFunctionParUsage(valueExpr, library, pointer, alloc, indirect);
             return (use>0) ? valueExpr : nullptr;
         }
         return nullptr;
@@ -1352,18 +1353,13 @@ const Token* CheckUninitVar::isVariableUsage(const Token *vartok, const Library&
     return derefValue ? derefValue : valueExpr;
 }
 
-const Token* CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer, Alloc alloc, int indirect) const
-{
-    return isVariableUsage(vartok, mSettings->library, pointer, alloc, indirect);
-}
-
 /***
  * Is function parameter "used" so a "usage of uninitialized variable" can
  * be written? If parameter is passed "by value" then it is "used". If it
  * is passed "by reference" then it is not necessarily "used".
  * @return  -1 => unknown   0 => not used   1 => used
  */
-int CheckUninitVar::isFunctionParUsage(const Token *vartok, const Library& library, bool pointer, Alloc alloc, int indirect)
+int CheckUninitVarImpl::isFunctionParUsage(const Token *vartok, const Library& library, bool pointer, Alloc alloc, int indirect)
 {
     bool unknown = false;
     const Token *parent = getAstParentSkipPossibleCastAndAddressOf(vartok, &unknown);
@@ -1433,12 +1429,12 @@ int CheckUninitVar::isFunctionParUsage(const Token *vartok, const Library& libra
     return -1;
 }
 
-int CheckUninitVar::isFunctionParUsage(const Token *vartok, bool pointer, Alloc alloc, int indirect) const
+int CheckUninitVarImpl::isFunctionParUsage(const Token *vartok, bool pointer, Alloc alloc, int indirect) const
 {
-    return CheckUninitVar::isFunctionParUsage(vartok, mSettings->library, pointer, alloc, indirect);
+    return isFunctionParUsage(vartok, mSettings->library, pointer, alloc, indirect);
 }
 
-bool CheckUninitVar::isMemberVariableAssignment(const Token *tok, const std::string &membervar) const
+bool CheckUninitVarImpl::isMemberVariableAssignment(const Token *tok, const std::string &membervar) const
 {
     if (Token::Match(tok, "%name% . %name%") && tok->strAt(2) == membervar) {
         if (Token::Match(tok->tokAt(3), "[=.[]"))
@@ -1507,7 +1503,7 @@ bool CheckUninitVar::isMemberVariableAssignment(const Token *tok, const std::str
     return false;
 }
 
-bool CheckUninitVar::isMemberVariableUsage(const Token *tok, bool isPointer, Alloc alloc, const std::string &membervar) const
+bool CheckUninitVarImpl::isMemberVariableUsage(const Token *tok, bool isPointer, Alloc alloc, const std::string &membervar) const
 {
     if (Token::Match(tok->previous(), "[(,] %name% . %name% [,)]") &&
         tok->strAt(2) == membervar) {
@@ -1523,7 +1519,7 @@ bool CheckUninitVar::isMemberVariableUsage(const Token *tok, bool isPointer, All
         const Token *parent = tok->next()->astParent();
         return !parent || !parent->isUnaryOp("&");
     }
-    if (!isPointer && !Token::simpleMatch(tok->astParent(), ".") && Token::Match(tok->previous(), "[(,] %name% [,)]") && isVariableUsage(tok, isPointer, alloc))
+    if (!isPointer && !Token::simpleMatch(tok->astParent(), ".") && Token::Match(tok->previous(), "[(,] %name% [,)]") && isVariableUsage(tok, mSettings->library, isPointer, alloc))
         return true;
 
     if (!isPointer && Token::Match(tok->previous(), "= %name% ;")) {
@@ -1543,18 +1539,18 @@ bool CheckUninitVar::isMemberVariableUsage(const Token *tok, bool isPointer, All
     if ((false) && // NOLINT(readability-simplify-boolean-expr,readability-redundant-parentheses)
         !isPointer &&
         Token::Match(tok->tokAt(-2), "[(,] & %name% [,)]") &&
-        isVariableUsage(tok, isPointer, alloc))
+        isVariableUsage(tok, mSettings->library,isPointer, alloc))
         return true;
 
     return false;
 }
 
-void CheckUninitVar::uninitdataError(const Token *tok, const std::string &varname)
+void CheckUninitVarImpl::uninitdataError(const Token *tok, const std::string &varname)
 {
     reportError(tok, Severity::error, "uninitdata", "$symbol:" + varname + "\nMemory is allocated but not initialized: $symbol", CWE_USE_OF_UNINITIALIZED_VARIABLE, Certainty::normal);
 }
 
-void CheckUninitVar::uninitvarError(const Token *tok, const std::string &varname, ErrorPath errorPath)
+void CheckUninitVarImpl::uninitvarError(const Token *tok, const std::string &varname, ErrorPath errorPath)
 {
     if (diag(tok))
         return;
@@ -1567,7 +1563,7 @@ void CheckUninitVar::uninitvarError(const Token *tok, const std::string &varname
                 Certainty::normal);
 }
 
-void CheckUninitVar::uninitvarError(const Token* tok, const ValueFlow::Value& v)
+void CheckUninitVarImpl::uninitvarError(const Token* tok, const ValueFlow::Value& v)
 {
     if (!mSettings->isEnabled(&v))
         return;
@@ -1604,7 +1600,7 @@ void CheckUninitVar::uninitvarError(const Token* tok, const ValueFlow::Value& v)
                 certainty);
 }
 
-void CheckUninitVar::uninitStructMemberError(const Token *tok, const std::string &membername)
+void CheckUninitVarImpl::uninitStructMemberError(const Token *tok, const std::string &membername)
 {
     reportError(tok,
                 Severity::error,
@@ -1612,7 +1608,7 @@ void CheckUninitVar::uninitStructMemberError(const Token *tok, const std::string
                 "$symbol:" + membername + "\nUninitialized struct member: $symbol", CWE_USE_OF_UNINITIALIZED_VARIABLE, Certainty::normal);
 }
 
-void CheckUninitVar::valueFlowUninit()
+void CheckUninitVarImpl::valueFlowUninit()
 {
     logChecker("CheckUninitVar::valueFlowUninit");
 
@@ -1696,7 +1692,7 @@ void CheckUninitVar::valueFlowUninit()
 static bool isVariableUsage(const Settings &settings, const Token *vartok, MathLib::bigint *value)
 {
     (void)value;
-    return CheckUninitVar::isVariableUsage(vartok, settings.library, true, CheckUninitVar::Alloc::ARRAY);
+    return CheckUninitVarImpl::isVariableUsage(vartok, settings.library, true, CheckUninitVarImpl::Alloc::ARRAY);
 }
 
 // a Clang-built executable will crash when using the anonymous MyFileInfo later on - so put it in a unique namespace for now
@@ -1752,7 +1748,7 @@ bool CheckUninitVar::analyseWholeProgram(const CTU::FileInfo &ctu, const std::li
 {
     (void)settings;
 
-    CheckUninitVar dummy(nullptr, &settings, &errorLogger);
+    CheckUninitVarImpl dummy(nullptr, &settings, &errorLogger);
     dummy.
     logChecker("CheckUninitVar::analyseWholeProgram");
 
@@ -1798,14 +1794,14 @@ bool CheckUninitVar::analyseWholeProgram(const CTU::FileInfo &ctu, const std::li
 
 void CheckUninitVar::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    CheckUninitVar checkUninitVar(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckUninitVarImpl checkUninitVar(&tokenizer, &tokenizer.getSettings(), errorLogger);
     checkUninitVar.valueFlowUninit();
     checkUninitVar.check();
 }
 
 void CheckUninitVar::getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const
 {
-    CheckUninitVar c(nullptr, settings, errorLogger);
+    CheckUninitVarImpl c(nullptr, settings, errorLogger);
 
     ValueFlow::Value v{};
 
diff --git a/lib/checkuninitvar.h b/lib/checkuninitvar.h
index b79e9c22be0..909905bb9d8 100644
--- a/lib/checkuninitvar.h
+++ b/lib/checkuninitvar.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 #include "mathlib.h"
 #include "errortypes.h"
@@ -61,20 +62,36 @@ class CPPCHECKLIB CheckUninitVar : public Check {
 
 public:
     /** @brief This constructor is used when registering the CheckUninitVar */
-    CheckUninitVar() : Check(myName()) {}
+    CheckUninitVar() : Check("Uninitialized variables") {}
 
-    enum Alloc : std::uint8_t { NO_ALLOC, NO_CTOR_CALL, CTOR_CALL, ARRAY };
+private:
+    /** @brief Run checks against the normal token list */
+    void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
-    static const Token *isVariableUsage(const Token *vartok, const Library &library, bool pointer, Alloc alloc, int indirect = 0);
-    const Token *isVariableUsage(const Token *vartok, bool pointer, Alloc alloc, int indirect = 0) const;
+    /** @brief Parse current TU and extract file info */
+    Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& /*currentConfig*/) const override;
 
-private:
+    Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override;
+
+    /** @brief Analyse all file infos for all TU */
+    bool analyseWholeProgram(const CTU::FileInfo &ctu, const std::list<Check::FileInfo*> &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override;
+
+    void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const override;
+
+    std::string classInfo() const override {
+        return "Uninitialized variables\n"
+               "- using uninitialized local variables\n"
+               "- using allocated data before it has been initialized\n";
+    }
+};
+
+class CPPCHECKLIB CheckUninitVarImpl : public CheckImpl {
+public:
     /** @brief This constructor is used when running checks. */
-    CheckUninitVar(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
+    CheckUninitVarImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
 
-    /** @brief Run checks against the normal token list */
-    void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
+    enum Alloc : std::uint8_t { NO_ALLOC, NO_CTOR_CALL, CTOR_CALL, ARRAY };
 
     bool diag(const Token* tok);
     /** Check for uninitialized variables */
@@ -92,17 +109,11 @@ class CPPCHECKLIB CheckUninitVar : public Check {
     bool isMemberVariableAssignment(const Token *tok, const std::string &membervar) const;
     bool isMemberVariableUsage(const Token *tok, bool isPointer, Alloc alloc, const std::string &membervar) const;
 
+    static const Token *isVariableUsage(const Token *vartok, const Library &library, bool pointer, Alloc alloc, int indirect = 0);
+
     /** ValueFlow-based checking for uninitialized variables */
     void valueFlowUninit();
 
-    /** @brief Parse current TU and extract file info */
-    Check::FileInfo *getFileInfo(const Tokenizer &tokenizer, const Settings &settings, const std::string& /*currentConfig*/) const override;
-
-    Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const override;
-
-    /** @brief Analyse all file infos for all TU */
-    bool analyseWholeProgram(const CTU::FileInfo &ctu, const std::list<Check::FileInfo*> &fileInfo, const Settings& settings, ErrorLogger &errorLogger) override;
-
     void uninitvarError(const Token* tok, const ValueFlow::Value& v);
     void uninitdataError(const Token *tok, const std::string &varname);
     void uninitvarError(const Token *tok, const std::string &varname, ErrorPath errorPath);
@@ -118,18 +129,6 @@ class CPPCHECKLIB CheckUninitVar : public Check {
     void uninitStructMemberError(const Token *tok, const std::string &membername);
 
     std::set<const Token*> mUninitDiags;
-
-    void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const override;
-
-    static std::string myName() {
-        return "Uninitialized variables";
-    }
-
-    std::string classInfo() const override {
-        return "Uninitialized variables\n"
-               "- using uninitialized local variables\n"
-               "- using allocated data before it has been initialized\n";
-    }
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp
index 9531237a208..4d8415e9793 100644
--- a/lib/checkunusedvar.cpp
+++ b/lib/checkunusedvar.cpp
@@ -699,7 +699,7 @@ static void useFunctionArgs(const Token *tok, Variables& variables)
 //---------------------------------------------------------------------------
 // Usage of function variables
 //---------------------------------------------------------------------------
-void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const scope, Variables& variables) const
+void CheckUnusedVarImpl::checkFunctionVariableUsage_iterateScopes(const Scope* const scope, Variables& variables) const
 {
     // Find declarations if the scope is executable..
     if (scope->isExecutable()) {
@@ -1173,7 +1173,7 @@ static bool isReturnedByRef(const Variable* var, const Function* func)
     });
 }
 
-void CheckUnusedVar::checkFunctionVariableUsage()
+void CheckUnusedVarImpl::checkFunctionVariableUsage()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->checkLibrary && !mSettings->isPremiumEnabled("unusedVariable"))
         return;
@@ -1479,7 +1479,7 @@ void CheckUnusedVar::checkFunctionVariableUsage()
     }
 }
 
-void CheckUnusedVar::unusedVariableError(const Token *tok, const std::string &varname)
+void CheckUnusedVarImpl::unusedVariableError(const Token *tok, const std::string &varname)
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedVariable"))
         return;
@@ -1487,7 +1487,7 @@ void CheckUnusedVar::unusedVariableError(const Token *tok, const std::string &va
     reportError(tok, Severity::style, "unusedVariable", "$symbol:" + varname + "\nUnused variable: $symbol", CWE563, Certainty::normal);
 }
 
-void CheckUnusedVar::allocatedButUnusedVariableError(const Token *tok, const std::string &varname)
+void CheckUnusedVarImpl::allocatedButUnusedVariableError(const Token *tok, const std::string &varname)
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedVariable"))
         return;
@@ -1495,7 +1495,7 @@ void CheckUnusedVar::allocatedButUnusedVariableError(const Token *tok, const std
     reportError(tok, Severity::style, "unusedAllocatedMemory", "$symbol:" + varname + "\nVariable '$symbol' is allocated memory that is never used.", CWE563, Certainty::normal);
 }
 
-void CheckUnusedVar::unreadVariableError(const Token *tok, const std::string &varname, bool modified)
+void CheckUnusedVarImpl::unreadVariableError(const Token *tok, const std::string &varname, bool modified)
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedVariable"))
         return;
@@ -1506,7 +1506,7 @@ void CheckUnusedVar::unreadVariableError(const Token *tok, const std::string &va
         reportError(tok, Severity::style, "unreadVariable", "$symbol:" + varname + "\nVariable '$symbol' is assigned a value that is never used.", CWE563, Certainty::normal);
 }
 
-void CheckUnusedVar::unassignedVariableError(const Token *tok, const std::string &varname)
+void CheckUnusedVarImpl::unassignedVariableError(const Token *tok, const std::string &varname)
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedVariable"))
         return;
@@ -1517,7 +1517,7 @@ void CheckUnusedVar::unassignedVariableError(const Token *tok, const std::string
 //---------------------------------------------------------------------------
 // Check that all struct members are used
 //---------------------------------------------------------------------------
-void CheckUnusedVar::checkStructMemberUsage()
+void CheckUnusedVarImpl::checkStructMemberUsage()
 {
     if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("unusedStructMember") && !mSettings->isPremiumEnabled("unusedVariable"))
         return;
@@ -1698,12 +1698,12 @@ void CheckUnusedVar::checkStructMemberUsage()
     }
 }
 
-void CheckUnusedVar::unusedStructMemberError(const Token* tok, const std::string& structname, const std::string& varname, const std::string& prefix)
+void CheckUnusedVarImpl::unusedStructMemberError(const Token* tok, const std::string& structname, const std::string& varname, const std::string& prefix)
 {
     reportError(tok, Severity::style, "unusedStructMember", "$symbol:" + structname + "::" + varname + '\n' + prefix + " member '$symbol' is never used.", CWE563, Certainty::normal);
 }
 
-bool CheckUnusedVar::isEmptyType(const Type* type)
+bool CheckUnusedVarImpl::isEmptyType(const Type* type)
 {
     // a type that has no variables and no constructor
 
@@ -1724,21 +1724,20 @@ bool CheckUnusedVar::isEmptyType(const Type* type)
     return (emptyType = false);
 }
 
-void CheckUnusedVar::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
-{
-    CheckUnusedVar checkUnusedVar(&tokenizer, &tokenizer.getSettings(), errorLogger);
+void CheckUnusedVar::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) {
+    CheckUnusedVarImpl checkUnusedVar(&tokenizer, &tokenizer.getSettings(), errorLogger);
 
     // Coding style checks
     checkUnusedVar.checkStructMemberUsage();
     checkUnusedVar.checkFunctionVariableUsage();
 }
 
-void CheckUnusedVar::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
-{
-    CheckUnusedVar c(nullptr, settings, errorLogger);
+void CheckUnusedVar::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
+    CheckUnusedVarImpl c(nullptr, settings, errorLogger);
     c.unusedVariableError(nullptr, "varname");
     c.allocatedButUnusedVariableError(nullptr, "varname");
     c.unreadVariableError(nullptr, "varname", false);
     c.unassignedVariableError(nullptr, "varname");
     c.unusedStructMemberError(nullptr, "structname", "variable");
 }
+
diff --git a/lib/checkunusedvar.h b/lib/checkunusedvar.h
index 5ab79514cf9..1d2227c15bf 100644
--- a/lib/checkunusedvar.h
+++ b/lib/checkunusedvar.h
@@ -22,6 +22,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <map>
@@ -46,16 +47,32 @@ class CPPCHECKLIB CheckUnusedVar : public Check {
 
 public:
     /** @brief This constructor is used when registering the CheckClass */
-    CheckUnusedVar() : Check(myName()) {}
+    CheckUnusedVar() : Check("UnusedVar") {}
 
 private:
-    /** @brief This constructor is used when running checks. */
-    CheckUnusedVar(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
-
     /** @brief Run checks against the normal token list */
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
+    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
+
+    std::string classInfo() const override {
+        return "UnusedVar checks\n"
+
+               // style
+               "- unused variable\n"
+               "- allocated but unused variable\n"
+               "- unread variable\n"
+               "- unassigned variable\n"
+               "- unused struct member\n";
+    }
+};
+
+class CPPCHECKLIB CheckUnusedVarImpl : public CheckImpl {
+public:
+    /** @brief This constructor is used when running checks. */
+    CheckUnusedVarImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
     /** @brief %Check for unused function variables */
     void checkFunctionVariableUsage_iterateScopes(const Scope* scope, Variables& variables) const;
     void checkFunctionVariableUsage();
@@ -72,25 +89,7 @@ class CPPCHECKLIB CheckUnusedVar : public Check {
     void unreadVariableError(const Token *tok, const std::string &varname, bool modified);
     void unassignedVariableError(const Token *tok, const std::string &varname);
 
-    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
-
-    static std::string myName() {
-        return "UnusedVar";
-    }
-
-    std::string classInfo() const override {
-        return "UnusedVar checks\n"
-
-               // style
-               "- unused variable\n"
-               "- allocated but unused variable\n"
-               "- unread variable\n"
-               "- unassigned variable\n"
-               "- unused struct member\n";
-    }
-
     std::map<const Type *,bool> mIsEmptyTypeMap;
-
 };
 /// @}
 //---------------------------------------------------------------------------
diff --git a/lib/checkvaarg.cpp b/lib/checkvaarg.cpp
index e6efc8f5ed9..18eb246e0e7 100644
--- a/lib/checkvaarg.cpp
+++ b/lib/checkvaarg.cpp
@@ -39,7 +39,7 @@ static const CWE CWE664(664U);   // Improper Control of a Resource Through its L
 static const CWE CWE688(688U);   // Function Call With Incorrect Variable or Reference as Argument
 static const CWE CWE758(758U);   // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior
 
-void CheckVaarg::va_start_argument()
+void CheckVaargImpl::va_start_argument()
 {
     const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
     const std::size_t functions = symbolDatabase->functionScopes.size();
@@ -73,13 +73,13 @@ void CheckVaarg::va_start_argument()
     }
 }
 
-void CheckVaarg::wrongParameterTo_va_start_error(const Token *tok, const std::string& paramIsName, const std::string& paramShouldName)
+void CheckVaargImpl::wrongParameterTo_va_start_error(const Token *tok, const std::string& paramIsName, const std::string& paramShouldName)
 {
     reportError(tok, Severity::warning,
                 "va_start_wrongParameter", "'" + paramIsName + "' given to va_start() is not last named argument of the function. Did you intend to pass '" + paramShouldName + "'?", CWE688, Certainty::normal);
 }
 
-void CheckVaarg::referenceAs_va_start_error(const Token *tok, const std::string& paramName)
+void CheckVaargImpl::referenceAs_va_start_error(const Token *tok, const std::string& paramName)
 {
     reportError(tok, Severity::error,
                 "va_start_referencePassed", "Using reference '" + paramName + "' as parameter for va_start() results in undefined behaviour.", CWE758, Certainty::normal);
@@ -90,7 +90,7 @@ void CheckVaarg::referenceAs_va_start_error(const Token *tok, const std::string&
 // Detect va_list usage after va_end()
 //---------------------------------------------------------------------------
 
-void CheckVaarg::va_list_usage()
+void CheckVaargImpl::va_list_usage()
 {
     if (mSettings->clang)
         return;
@@ -155,19 +155,19 @@ void CheckVaarg::va_list_usage()
     }
 }
 
-void CheckVaarg::va_end_missingError(const Token *tok, const std::string& varname)
+void CheckVaargImpl::va_end_missingError(const Token *tok, const std::string& varname)
 {
     reportError(tok, Severity::error,
                 "va_end_missing", "va_list '" + varname + "' was opened but not closed by va_end().", CWE664, Certainty::normal);
 }
 
-void CheckVaarg::va_list_usedBeforeStartedError(const Token *tok, const std::string& varname)
+void CheckVaargImpl::va_list_usedBeforeStartedError(const Token *tok, const std::string& varname)
 {
     reportError(tok, Severity::error,
                 "va_list_usedBeforeStarted", "va_list '" + varname + "' used before va_start() was called.", CWE664, Certainty::normal);
 }
 
-void CheckVaarg::va_start_subsequentCallsError(const Token *tok, const std::string& varname)
+void CheckVaargImpl::va_start_subsequentCallsError(const Token *tok, const std::string& varname)
 {
     reportError(tok, Severity::error,
                 "va_start_subsequentCalls", "va_start() or va_copy() called subsequently on '" + varname + "' without va_end() in between.", CWE664, Certainty::normal);
@@ -175,14 +175,14 @@ void CheckVaarg::va_start_subsequentCallsError(const Token *tok, const std::stri
 
 void CheckVaarg::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
 {
-    CheckVaarg check(&tokenizer, &tokenizer.getSettings(), errorLogger);
+    CheckVaargImpl check(&tokenizer, &tokenizer.getSettings(), errorLogger);
     check.va_start_argument();
     check.va_list_usage();
 }
 
 void CheckVaarg::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
 {
-    CheckVaarg c(nullptr, settings, errorLogger);
+    CheckVaargImpl c(nullptr, settings, errorLogger);
     c.wrongParameterTo_va_start_error(nullptr, "arg1", "arg2");
     c.referenceAs_va_start_error(nullptr, "arg1");
     c.va_end_missingError(nullptr, "vl");
diff --git a/lib/checkvaarg.h b/lib/checkvaarg.h
index 7af5d98d66f..e07d653456a 100644
--- a/lib/checkvaarg.h
+++ b/lib/checkvaarg.h
@@ -23,6 +23,7 @@
 //---------------------------------------------------------------------------
 
 #include "check.h"
+#include "checkimpl.h"
 #include "config.h"
 
 #include <string>
@@ -41,29 +42,13 @@ class Tokenizer;
 
 class CPPCHECKLIB CheckVaarg : public Check {
 public:
-    CheckVaarg() : Check(myName()) {}
-
-private:
-    CheckVaarg(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
-        : Check(myName(), tokenizer, settings, errorLogger) {}
+    CheckVaarg() : Check("Vaarg") {}
 
     void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override;
 
-    void va_start_argument();
-    void va_list_usage();
-
-    void wrongParameterTo_va_start_error(const Token *tok, const std::string& paramIsName, const std::string& paramShouldName);
-    void referenceAs_va_start_error(const Token *tok, const std::string& paramName);
-    void va_end_missingError(const Token *tok, const std::string& varname);
-    void va_list_usedBeforeStartedError(const Token *tok, const std::string& varname);
-    void va_start_subsequentCallsError(const Token *tok, const std::string& varname);
-
+private:
     void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override;
 
-    static std::string myName() {
-        return "Vaarg";
-    }
-
     std::string classInfo() const override {
         return "Check for misusage of variable argument lists:\n"
                "- Wrong parameter passed to va_start()\n"
@@ -74,6 +59,22 @@ class CPPCHECKLIB CheckVaarg : public Check {
     }
 };
 
+class CPPCHECKLIB CheckVaargImpl : public CheckImpl
+{
+public:
+    CheckVaargImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+        : CheckImpl(tokenizer, settings, errorLogger) {}
+
+    void va_start_argument();
+    void va_list_usage();
+
+    void wrongParameterTo_va_start_error(const Token *tok, const std::string& paramIsName, const std::string& paramShouldName);
+    void referenceAs_va_start_error(const Token *tok, const std::string& paramName);
+    void va_end_missingError(const Token *tok, const std::string& varname);
+    void va_list_usedBeforeStartedError(const Token *tok, const std::string& varname);
+    void va_start_subsequentCallsError(const Token *tok, const std::string& varname);
+};
+
 /// @}
 
 //---------------------------------------------------------------------------
diff --git a/lib/cppcheck.vcxproj b/lib/cppcheck.vcxproj
index 12bd4898d4a..5e5b9ae743a 100644
--- a/lib/cppcheck.vcxproj
+++ b/lib/cppcheck.vcxproj
@@ -32,12 +32,6 @@
     <ClCompile Include="addoninfo.cpp" />
     <ClCompile Include="analyzerinfo.cpp" />
     <ClCompile Include="astutils.cpp" />
-    <ClCompile Include="check.cpp">
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release-PCRE|x64'">Create</PrecompiledHeader>
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug-PCRE|x64'">Create</PrecompiledHeader>
-    </ClCompile>
     <ClCompile Include="check64bit.cpp" />
     <ClCompile Include="checkassert.cpp" />
     <ClCompile Include="checkautovariables.cpp" />
@@ -50,6 +44,12 @@
     <ClCompile Include="checkersreport.cpp" />
     <ClCompile Include="checkexceptionsafety.cpp" />
     <ClCompile Include="checkfunctions.cpp" />
+    <ClCompile Include="checkimpl.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release-PCRE|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug-PCRE|x64'">Create</PrecompiledHeader>
+    </ClCompile>
     <ClCompile Include="checkinternal.cpp" />
     <ClCompile Include="checkio.cpp" />
     <ClCompile Include="checkleakautovar.cpp" />
@@ -124,6 +124,7 @@
     <ClInclude Include="checkersreport.h" />
     <ClInclude Include="checkexceptionsafety.h" />
     <ClInclude Include="checkfunctions.h" />
+    <ClInclude Include="checkimpl.h" />
     <ClInclude Include="checkinternal.h" />
     <ClInclude Include="checkio.h" />
     <ClInclude Include="checkleakautovar.h" />
diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp
index 3819bfc4b41..246bd9eaf40 100644
--- a/lib/valueflow.cpp
+++ b/lib/valueflow.cpp
@@ -5697,7 +5697,7 @@ static void valueFlowSubFunction(const TokenList& tokenlist,
                 // Remove uninit values if argument is passed by value
                 if (argtok->variable() && !argtok->variable()->isPointer() && argvalues.size() == 1 &&
                     argvalues.front().isUninitValue()) {
-                    if (CheckUninitVar::isVariableUsage(argtok, settings.library, false, CheckUninitVar::Alloc::NO_ALLOC, 0))
+                    if (CheckUninitVarImpl::isVariableUsage(argtok, settings.library, false, CheckUninitVarImpl::Alloc::NO_ALLOC, 0))
                         continue;
                 }
 
diff --git a/oss-fuzz/Makefile b/oss-fuzz/Makefile
index c93b8694065..bf40964b338 100644
--- a/oss-fuzz/Makefile
+++ b/oss-fuzz/Makefile
@@ -45,7 +45,6 @@ LIBOBJ =      $(libcppdir)/valueflow.o \
               $(libcppdir)/addoninfo.o \
               $(libcppdir)/analyzerinfo.o \
               $(libcppdir)/astutils.o \
-              $(libcppdir)/check.o \
               $(libcppdir)/check64bit.o \
               $(libcppdir)/checkassert.o \
               $(libcppdir)/checkautovariables.o \
@@ -58,6 +57,7 @@ LIBOBJ =      $(libcppdir)/valueflow.o \
               $(libcppdir)/checkersreport.o \
               $(libcppdir)/checkexceptionsafety.o \
               $(libcppdir)/checkfunctions.o \
+              $(libcppdir)/checkimpl.o \
               $(libcppdir)/checkinternal.o \
               $(libcppdir)/checkio.o \
               $(libcppdir)/checkleakautovar.o \
@@ -153,7 +153,7 @@ simplecpp.o: ../externals/simplecpp/simplecpp.cpp ../externals/simplecpp/simplec
 tinyxml2.o: ../externals/tinyxml2/tinyxml2.cpp ../externals/tinyxml2/tinyxml2.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -w -D_LARGEFILE_SOURCE -c -o $@ ../externals/tinyxml2/tinyxml2.cpp
 
-$(libcppdir)/valueflow.o: ../lib/valueflow.cpp ../lib/addoninfo.h ../lib/analyzer.h ../lib/astutils.h ../lib/calculate.h ../lib/check.h ../lib/checkers.h ../lib/checkuninitvar.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/findtoken.h ../lib/forwardanalyzer.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/programmemory.h ../lib/regex.h ../lib/reverseanalyzer.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/timer.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vf_analyzers.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h
+$(libcppdir)/valueflow.o: ../lib/valueflow.cpp ../lib/addoninfo.h ../lib/analyzer.h ../lib/astutils.h ../lib/calculate.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkuninitvar.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/findtoken.h ../lib/forwardanalyzer.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/programmemory.h ../lib/regex.h ../lib/reverseanalyzer.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/timer.h ../lib/token.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vf_analyzers.h ../lib/vf_common.h ../lib/vf_settokenvalue.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/valueflow.cpp
 
 $(libcppdir)/tokenize.o: ../lib/tokenize.cpp ../externals/simplecpp/simplecpp.h ../lib/addoninfo.h ../lib/astutils.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/preprocessor.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/summaries.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/timer.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h
@@ -168,31 +168,28 @@ $(libcppdir)/addoninfo.o: ../lib/addoninfo.cpp ../externals/picojson/picojson.h
 $(libcppdir)/analyzerinfo.o: ../lib/analyzerinfo.cpp ../externals/tinyxml2/tinyxml2.h ../lib/analyzerinfo.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/filesettings.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/standards.h ../lib/utils.h ../lib/xml.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/analyzerinfo.cpp
 
-$(libcppdir)/astutils.o: ../lib/astutils.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkclass.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/findtoken.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vfvalue.h
+$(libcppdir)/astutils.o: ../lib/astutils.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkclass.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/findtoken.h ../lib/infer.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/utils.h ../lib/valueflow.h ../lib/valueptr.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/astutils.cpp
 
-$(libcppdir)/check.o: ../lib/check.cpp ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
-	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/check.cpp
-
-$(libcppdir)/check64bit.o: ../lib/check64bit.cpp ../lib/addoninfo.h ../lib/check.h ../lib/check64bit.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
+$(libcppdir)/check64bit.o: ../lib/check64bit.cpp ../lib/addoninfo.h ../lib/check.h ../lib/check64bit.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/check64bit.cpp
 
-$(libcppdir)/checkassert.o: ../lib/checkassert.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkassert.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
+$(libcppdir)/checkassert.o: ../lib/checkassert.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkassert.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkassert.cpp
 
-$(libcppdir)/checkautovariables.o: ../lib/checkautovariables.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkautovariables.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h
+$(libcppdir)/checkautovariables.o: ../lib/checkautovariables.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkautovariables.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkautovariables.cpp
 
-$(libcppdir)/checkbool.o: ../lib/checkbool.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkbool.h ../lib/checkers.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
+$(libcppdir)/checkbool.o: ../lib/checkbool.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkbool.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbool.cpp
 
-$(libcppdir)/checkbufferoverrun.o: ../lib/checkbufferoverrun.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkbufferoverrun.h ../lib/checkers.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vf_common.h ../lib/vfvalue.h ../lib/xml.h
+$(libcppdir)/checkbufferoverrun.o: ../lib/checkbufferoverrun.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkbufferoverrun.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vf_common.h ../lib/vfvalue.h ../lib/xml.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkbufferoverrun.cpp
 
-$(libcppdir)/checkclass.o: ../lib/checkclass.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkclass.h ../lib/checkers.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h
+$(libcppdir)/checkclass.o: ../lib/checkclass.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkclass.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkclass.cpp
 
-$(libcppdir)/checkcondition.o: ../lib/checkcondition.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkcondition.h ../lib/checkers.h ../lib/checkother.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
+$(libcppdir)/checkcondition.o: ../lib/checkcondition.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkcondition.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkother.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkcondition.cpp
 
 $(libcppdir)/checkers.o: ../lib/checkers.cpp ../lib/checkers.h ../lib/config.h
@@ -204,58 +201,61 @@ $(libcppdir)/checkersidmapping.o: ../lib/checkersidmapping.cpp ../lib/checkers.h
 $(libcppdir)/checkersreport.o: ../lib/checkersreport.cpp ../lib/addoninfo.h ../lib/checkers.h ../lib/checkersreport.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/standards.h ../lib/utils.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkersreport.cpp
 
-$(libcppdir)/checkexceptionsafety.o: ../lib/checkexceptionsafety.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkexceptionsafety.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
+$(libcppdir)/checkexceptionsafety.o: ../lib/checkexceptionsafety.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkexceptionsafety.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkexceptionsafety.cpp
 
-$(libcppdir)/checkfunctions.o: ../lib/checkfunctions.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkfunctions.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h
+$(libcppdir)/checkfunctions.o: ../lib/checkfunctions.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkfunctions.h ../lib/checkimpl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkfunctions.cpp
 
-$(libcppdir)/checkinternal.o: ../lib/checkinternal.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkinternal.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
+$(libcppdir)/checkimpl.o: ../lib/checkimpl.cpp ../lib/addoninfo.h ../lib/checkers.h ../lib/checkimpl.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/standards.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
+	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkimpl.cpp
+
+$(libcppdir)/checkinternal.o: ../lib/checkinternal.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkinternal.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkinternal.cpp
 
-$(libcppdir)/checkio.o: ../lib/checkio.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkio.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
+$(libcppdir)/checkio.o: ../lib/checkio.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkio.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkio.cpp
 
-$(libcppdir)/checkleakautovar.o: ../lib/checkleakautovar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkleakautovar.h ../lib/checkmemoryleak.h ../lib/checknullpointer.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
+$(libcppdir)/checkleakautovar.o: ../lib/checkleakautovar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkleakautovar.h ../lib/checkmemoryleak.h ../lib/checknullpointer.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkleakautovar.cpp
 
-$(libcppdir)/checkmemoryleak.o: ../lib/checkmemoryleak.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkmemoryleak.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
+$(libcppdir)/checkmemoryleak.o: ../lib/checkmemoryleak.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkmemoryleak.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkmemoryleak.cpp
 
-$(libcppdir)/checknullpointer.o: ../lib/checknullpointer.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checknullpointer.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/findtoken.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h
+$(libcppdir)/checknullpointer.o: ../lib/checknullpointer.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checknullpointer.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/findtoken.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checknullpointer.cpp
 
-$(libcppdir)/checkother.o: ../lib/checkother.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkother.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h
+$(libcppdir)/checkother.o: ../lib/checkother.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkother.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkother.cpp
 
-$(libcppdir)/checkpostfixoperator.o: ../lib/checkpostfixoperator.cpp ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/checkpostfixoperator.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
+$(libcppdir)/checkpostfixoperator.o: ../lib/checkpostfixoperator.cpp ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkpostfixoperator.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkpostfixoperator.cpp
 
-$(libcppdir)/checks.o: ../lib/checks.cpp ../lib/check.h ../lib/check64bit.h ../lib/checkassert.h ../lib/checkautovariables.h ../lib/checkbool.h ../lib/checkbufferoverrun.h ../lib/checkclass.h ../lib/checkcondition.h ../lib/checkexceptionsafety.h ../lib/checkfunctions.h ../lib/checkinternal.h ../lib/checkio.h ../lib/checkleakautovar.h ../lib/checkmemoryleak.h ../lib/checknullpointer.h ../lib/checkother.h ../lib/checkpostfixoperator.h ../lib/checks.h ../lib/checksizeof.h ../lib/checkstl.h ../lib/checkstring.h ../lib/checktype.h ../lib/checkuninitvar.h ../lib/checkunusedvar.h ../lib/checkvaarg.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/standards.h ../lib/vfvalue.h
+$(libcppdir)/checks.o: ../lib/checks.cpp ../lib/check.h ../lib/check64bit.h ../lib/checkassert.h ../lib/checkautovariables.h ../lib/checkbool.h ../lib/checkbufferoverrun.h ../lib/checkclass.h ../lib/checkcondition.h ../lib/checkexceptionsafety.h ../lib/checkfunctions.h ../lib/checkimpl.h ../lib/checkinternal.h ../lib/checkio.h ../lib/checkleakautovar.h ../lib/checkmemoryleak.h ../lib/checknullpointer.h ../lib/checkother.h ../lib/checkpostfixoperator.h ../lib/checks.h ../lib/checksizeof.h ../lib/checkstl.h ../lib/checkstring.h ../lib/checktype.h ../lib/checkuninitvar.h ../lib/checkunusedvar.h ../lib/checkvaarg.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/standards.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checks.cpp
 
-$(libcppdir)/checksizeof.o: ../lib/checksizeof.cpp ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/checksizeof.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
+$(libcppdir)/checksizeof.o: ../lib/checksizeof.cpp ../lib/addoninfo.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checksizeof.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checksizeof.cpp
 
-$(libcppdir)/checkstl.o: ../lib/checkstl.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checknullpointer.h ../lib/checkstl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/pathanalysis.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h
+$(libcppdir)/checkstl.o: ../lib/checkstl.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checknullpointer.h ../lib/checkstl.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/pathanalysis.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkstl.cpp
 
-$(libcppdir)/checkstring.o: ../lib/checkstring.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkstring.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
+$(libcppdir)/checkstring.o: ../lib/checkstring.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkstring.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkstring.cpp
 
-$(libcppdir)/checktype.o: ../lib/checktype.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checktype.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h
+$(libcppdir)/checktype.o: ../lib/checktype.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checktype.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checktype.cpp
 
-$(libcppdir)/checkuninitvar.o: ../lib/checkuninitvar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checknullpointer.h ../lib/checkuninitvar.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
+$(libcppdir)/checkuninitvar.o: ../lib/checkuninitvar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checknullpointer.h ../lib/checkuninitvar.h ../lib/config.h ../lib/ctu.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkuninitvar.cpp
 
 $(libcppdir)/checkunusedfunctions.o: ../lib/checkunusedfunctions.cpp ../externals/tinyxml2/tinyxml2.h ../lib/addoninfo.h ../lib/analyzerinfo.h ../lib/astutils.h ../lib/checkers.h ../lib/checkunusedfunctions.h ../lib/config.h ../lib/errorlogger.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/path.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h ../lib/xml.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkunusedfunctions.cpp
 
-$(libcppdir)/checkunusedvar.o: ../lib/checkunusedvar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkunusedvar.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h
+$(libcppdir)/checkunusedvar.o: ../lib/checkunusedvar.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkunusedvar.h ../lib/config.h ../lib/errortypes.h ../lib/fwdanalysis.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/valueflow.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkunusedvar.cpp
 
-$(libcppdir)/checkvaarg.o: ../lib/checkvaarg.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkvaarg.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
+$(libcppdir)/checkvaarg.o: ../lib/checkvaarg.cpp ../lib/addoninfo.h ../lib/astutils.h ../lib/check.h ../lib/checkers.h ../lib/checkimpl.h ../lib/checkvaarg.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/platform.h ../lib/regex.h ../lib/settings.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
 	$(CXX) ${LIB_FUZZING_ENGINE} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/checkvaarg.cpp
 
 $(libcppdir)/clangimport.o: ../lib/clangimport.cpp ../lib/clangimport.h ../lib/config.h ../lib/errortypes.h ../lib/library.h ../lib/mathlib.h ../lib/smallvector.h ../lib/sourcelocation.h ../lib/standards.h ../lib/symboldatabase.h ../lib/templatesimplifier.h ../lib/token.h ../lib/tokenize.h ../lib/tokenlist.h ../lib/utils.h ../lib/vfvalue.h
diff --git a/test/test64bit.cpp b/test/test64bit.cpp
index 6f9a5fbda2f..da837fd9a96 100644
--- a/test/test64bit.cpp
+++ b/test/test64bit.cpp
@@ -49,8 +49,7 @@ class Test64BitPortability : public TestFixture {
         SimpleTokenizer tokenizer(settings, *this, cpp);
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
-        // Check char variable usage..
-        Check64BitPortability check64BitPortability(&tokenizer, &settings, this);
+        Check64BitPortabilityImpl check64BitPortability(&tokenizer, &settings, this);
         check64BitPortability.pointerassignment();
     }
 
diff --git a/test/testcharvar.cpp b/test/testcharvar.cpp
index 624efcff539..bb98dfad48d 100644
--- a/test/testcharvar.cpp
+++ b/test/testcharvar.cpp
@@ -47,7 +47,7 @@ class TestCharVar : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check char variable usage..
-        CheckOther checkOther(&tokenizer, &settings, this);
+        CheckOtherImpl checkOther(&tokenizer, &settings, this);
         checkOther.checkCharVariable();
     }
 
diff --git a/test/testclass.cpp b/test/testclass.cpp
index c1b801c208b..35994e98cf4 100644
--- a/test/testclass.cpp
+++ b/test/testclass.cpp
@@ -270,7 +270,7 @@ class TestClass : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check..
-        CheckClass checkClass(&tokenizer, &settings, this);
+        CheckClassImpl checkClass(&tokenizer, &settings, this);
         (checkClass.checkCopyCtorAndEqOperator)();
     }
 
@@ -371,7 +371,7 @@ class TestClass : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check..
-        CheckClass checkClass(&tokenizer, &settings0, this);
+        CheckClassImpl checkClass(&tokenizer, &settings0, this);
         (checkClass.checkExplicitConstructors)();
     }
 
@@ -528,7 +528,7 @@ class TestClass : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check..
-        CheckClass checkClass(&tokenizer, &settings1, this);
+        CheckClassImpl checkClass(&tokenizer, &settings1, this);
         (checkClass.checkDuplInheritedMembers)();
     }
 
@@ -752,7 +752,7 @@ class TestClass : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check..
-        CheckClass checkClass(&tokenizer, &settings3, this);
+        CheckClassImpl checkClass(&tokenizer, &settings3, this);
         checkClass.copyconstructors();
     }
 
@@ -1223,7 +1223,7 @@ class TestClass : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check..
-        CheckClass checkClass(&tokenizer, &settings0, this);
+        CheckClassImpl checkClass(&tokenizer, &settings0, this);
         checkClass.operatorEqRetRefThis();
     }
 
@@ -1694,7 +1694,7 @@ class TestClass : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check..
-        CheckClass checkClass(&tokenizer, &settings1, this);
+        CheckClassImpl checkClass(&tokenizer, &settings1, this);
         checkClass.operatorEqToSelf();
     }
 
@@ -2657,7 +2657,7 @@ class TestClass : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check..
-        CheckClass checkClass(&tokenizer, &s, this);
+        CheckClassImpl checkClass(&tokenizer, &s, this);
         checkClass.virtualDestructor();
     }
 
@@ -2994,7 +2994,7 @@ class TestClass : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check..
-        CheckClass checkClass(&tokenizer, &settings, this);
+        CheckClassImpl checkClass(&tokenizer, &settings, this);
         checkClass.checkMemset();
     }
 
@@ -3640,7 +3640,7 @@ class TestClass : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check..
-        CheckClass checkClass(&tokenizer, &settings1, this);
+        CheckClassImpl checkClass(&tokenizer, &settings1, this);
         checkClass.thisSubtraction();
     }
 
@@ -3680,7 +3680,7 @@ class TestClass : public TestFixture {
         SimpleTokenizer tokenizer(settings, *this);
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
-        CheckClass checkClass(&tokenizer, &settings, this);
+        CheckClassImpl checkClass(&tokenizer, &settings, this);
         (checkClass.checkConst)();
     }
 
@@ -7863,7 +7863,7 @@ class TestClass : public TestFixture {
         SimpleTokenizer tokenizer(settings2, *this);
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
-        CheckClass checkClass(&tokenizer, &settings2, this);
+        CheckClassImpl checkClass(&tokenizer, &settings2, this);
         checkClass.initializerListOrder();
     }
 
@@ -8017,7 +8017,7 @@ class TestClass : public TestFixture {
         SimpleTokenizer tokenizer(settings, *this);
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
-        CheckClass checkClass(&tokenizer, &settings, this);
+        CheckClassImpl checkClass(&tokenizer, &settings, this);
         checkClass.initializationListUsage();
     }
 
@@ -8241,7 +8241,7 @@ class TestClass : public TestFixture {
         SimpleTokenizer tokenizer(settings0, *this);
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
-        CheckClass checkClass(&tokenizer, &settings0, this);
+        CheckClassImpl checkClass(&tokenizer, &settings0, this);
         (checkClass.checkSelfInitialization)();
     }
 
@@ -8351,7 +8351,7 @@ class TestClass : public TestFixture {
         SimpleTokenizer tokenizer(settings, *this);
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
-        CheckClass checkClass(&tokenizer, &settings, this);
+        CheckClassImpl checkClass(&tokenizer, &settings, this);
         checkClass.checkVirtualFunctionCallInConstructor();
     }
 
@@ -8696,7 +8696,7 @@ class TestClass : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check..
-        CheckClass checkClass(&tokenizer, &settings, this);
+        CheckClassImpl checkClass(&tokenizer, &settings, this);
         (checkClass.checkOverride)();
     }
 
@@ -8908,7 +8908,7 @@ class TestClass : public TestFixture {
         ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line);
 
         // Check..
-        CheckClass checkClass(&tokenizer, &settings, this);
+        CheckClassImpl checkClass(&tokenizer, &settings, this);
         (checkClass.checkUselessOverride)();
     }
 
@@ -9098,7 +9098,7 @@ class TestClass : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check..
-        CheckClass checkClass(&tokenizer, &settings, this);
+        CheckClassImpl checkClass(&tokenizer, &settings, this);
         (checkClass.checkUnsafeClassRefMember)();
     }
 
@@ -9116,7 +9116,7 @@ class TestClass : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check..
-        CheckClass checkClass(&tokenizer, &settings1, this);
+        CheckClassImpl checkClass(&tokenizer, &settings1, this);
         (checkClass.checkThisUseAfterFree)();
     }
 
@@ -9353,7 +9353,7 @@ class TestClass : public TestFixture {
         ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line);
 
         // Check..
-        CheckClass checkClass(&tokenizer, &settings, this);
+        CheckClassImpl checkClass(&tokenizer, &settings, this);
         (checkClass.checkReturnByReference)();
     }
 
diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp
index 0eb91ba8cca..8bec74529b6 100644
--- a/test/testconstructors.cpp
+++ b/test/testconstructors.cpp
@@ -52,7 +52,7 @@ class TestConstructors : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check class constructors..
-        CheckClass checkClass(&tokenizer, &settings1, this);
+        CheckClassImpl checkClass(&tokenizer, &settings1, this);
         checkClass.constructors();
     }
 
diff --git a/test/testincompletestatement.cpp b/test/testincompletestatement.cpp
index 3d8f5d4d713..bd94b52af0e 100644
--- a/test/testincompletestatement.cpp
+++ b/test/testincompletestatement.cpp
@@ -50,7 +50,7 @@ class TestIncompleteStatement : public TestFixture {
         ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line);
 
         // Check for incomplete statements..
-        CheckOther checkOther(&tokenizer, &settings1, this);
+        CheckOtherImpl checkOther(&tokenizer, &settings1, this);
         checkOther.checkIncompleteStatement();
     }
 
diff --git a/test/testio.cpp b/test/testio.cpp
index d3344f76b8d..bc6e40034f6 100644
--- a/test/testio.cpp
+++ b/test/testio.cpp
@@ -109,7 +109,7 @@ class TestIO : public TestFixture {
 
         // Check..
         if (options.onlyFormatStr) {
-            CheckIO checkIO(&tokenizer, &settings1, this);
+            CheckIOImpl checkIO(&tokenizer, &settings1, this);
             checkIO.checkWrongPrintfScanfArguments();
             return;
         }
diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp
index 1ed88120886..8982215d8e3 100644
--- a/test/testmemleak.cpp
+++ b/test/testmemleak.cpp
@@ -39,13 +39,12 @@ class TestMemleak : public TestFixture {
 
 #define functionReturnType(...) functionReturnType_(__FILE__, __LINE__, __VA_ARGS__)
     template<size_t size>
-    CheckMemoryLeak::AllocType functionReturnType_(const char* file, int line, const char (&code)[size]) {
+    CheckMemoryLeakImpl::AllocType functionReturnType_(const char* file, int line, const char (&code)[size]) {
         // Tokenize..
         SimpleTokenizer tokenizer(settingsDefault, *this);
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
-        const CheckMemoryLeak c(&tokenizer, this, &settingsDefault);
-
+        const CheckMemoryLeakImpl c(&tokenizer, &settingsDefault, this);
         return (c.functionReturnType)(&tokenizer.getSymbolDatabase()->scopeList.front().functionList.front());
     }
 
@@ -53,19 +52,19 @@ class TestMemleak : public TestFixture {
         {
             const char code[] = "const char *foo()\n"
                                 "{ return 0; }";
-            ASSERT_EQUALS(CheckMemoryLeak::No, functionReturnType(code));
+            ASSERT_EQUALS(CheckMemoryLeakImpl::No, functionReturnType(code));
         }
 
         {
             const char code[] = "Fred *newFred()\n"
                                 "{ return new Fred; }";
-            ASSERT_EQUALS(CheckMemoryLeak::New, functionReturnType(code));
+            ASSERT_EQUALS(CheckMemoryLeakImpl::New, functionReturnType(code));
         }
 
         {
             const char code[] = "char *foo()\n"
                                 "{ return new char[100]; }";
-            ASSERT_EQUALS(CheckMemoryLeak::NewArray, functionReturnType(code));
+            ASSERT_EQUALS(CheckMemoryLeakImpl::NewArray, functionReturnType(code));
         }
 
         {
@@ -74,7 +73,7 @@ class TestMemleak : public TestFixture {
                                 "    char *p = new char[100];\n"
                                 "    return p;\n"
                                 "}";
-            ASSERT_EQUALS(CheckMemoryLeak::NewArray, functionReturnType(code));
+            ASSERT_EQUALS(CheckMemoryLeakImpl::NewArray, functionReturnType(code));
         }
     }
 
@@ -94,8 +93,8 @@ class TestMemleak : public TestFixture {
 
         // there is no allocation
         const Token *tok = Token::findsimplematch(tokenizer.tokens(), "ret =");
-        const CheckMemoryLeak check(&tokenizer, nullptr, &settingsDefault);
-        ASSERT_EQUALS(CheckMemoryLeak::No, check.getAllocationType(tok->tokAt(2), 1));
+        const CheckMemoryLeakImpl check(&tokenizer, &settingsDefault, nullptr);
+        ASSERT_EQUALS(CheckMemoryLeakImpl::No, check.getAllocationType(tok->tokAt(2), 1));
     }
 };
 
@@ -120,7 +119,7 @@ class TestMemleakInFunction : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check for memory leaks..
-        CheckMemoryLeakInFunction checkMemoryLeak(&tokenizer, &settings, this);
+        CheckMemoryLeakInFunctionImpl checkMemoryLeak(&tokenizer, &settings, this);
         checkMemoryLeak.checkReallocUsage();
     }
 
@@ -502,7 +501,7 @@ class TestMemleakInClass : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check for memory leaks..
-        CheckMemoryLeakInClass checkMemoryLeak(&tokenizer, &settings, this);
+        CheckMemoryLeakInClassImpl checkMemoryLeak(&tokenizer, &settings, this);
         (checkMemoryLeak.check)();
     }
 
@@ -1707,7 +1706,7 @@ class TestMemleakStructMember : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check for memory leaks..
-        CheckMemoryLeakStructMember checkMemoryLeakStructMember(&tokenizer, &settings, this);
+        CheckMemoryLeakStructMemberImpl checkMemoryLeakStructMember(&tokenizer, &settings, this);
         (checkMemoryLeakStructMember.check)();
     }
 
@@ -2389,7 +2388,7 @@ class TestMemleakNoVar : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check for memory leaks..
-        CheckMemoryLeakNoVar checkMemoryLeakNoVar(&tokenizer, &settings, this);
+        CheckMemoryLeakNoVarImpl checkMemoryLeakNoVar(&tokenizer, &settings, this);
         (checkMemoryLeakNoVar.check)();
     }
 
diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp
index a154bd0d9c2..3e9d4011500 100644
--- a/test/testnullpointer.cpp
+++ b/test/testnullpointer.cpp
@@ -4351,7 +4351,7 @@ class TestNullPointer : public TestFixture {
             Library library;
             ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata)));
 
-            const std::list<const Token *> null = CheckNullPointer::parseFunctionCall(*xtok, library);
+            const std::list<const Token *> null = CheckNullPointerImpl::parseFunctionCall(*xtok, library);
             ASSERT_EQUALS(0U, null.size());
         }
 
@@ -4369,7 +4369,7 @@ class TestNullPointer : public TestFixture {
             Library library;
             ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata)));
 
-            const std::list<const Token *> null = CheckNullPointer::parseFunctionCall(*xtok, library);
+            const std::list<const Token *> null = CheckNullPointerImpl::parseFunctionCall(*xtok, library);
             ASSERT_EQUALS(1U, null.size());
             ASSERT_EQUALS("a", null.front()->str());
         }
diff --git a/test/testother.cpp b/test/testother.cpp
index 9a18a067231..321657c668f 100644
--- a/test/testother.cpp
+++ b/test/testother.cpp
@@ -2055,7 +2055,7 @@ class TestOther : public TestFixture {
         SimpleTokenizer tokenizerCpp(settings, *this);
         ASSERT_LOC(tokenizerCpp.tokenize(code), file, line);
 
-        CheckOther checkOtherCpp(&tokenizerCpp, &settings, this);
+        CheckOtherImpl checkOtherCpp(&tokenizerCpp, &settings, this);
         checkOtherCpp.warningOldStylePointerCast();
         checkOtherCpp.warningDangerousTypeCast();
     }
@@ -2341,7 +2341,7 @@ class TestOther : public TestFixture {
         SimpleTokenizer tokenizerCpp(settings, *this);
         ASSERT_LOC(tokenizerCpp.tokenize(code), file, line);
 
-        CheckOther checkOtherCpp(&tokenizerCpp, &settings, this);
+        CheckOtherImpl checkOtherCpp(&tokenizerCpp, &settings, this);
         checkOtherCpp.warningIntToPointerCast();
     }
 
@@ -2380,7 +2380,7 @@ class TestOther : public TestFixture {
         SimpleTokenizer tokenizer(settings, *this);
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
-        CheckOther checkOtherCpp(&tokenizer, &settings, this);
+        CheckOtherImpl checkOtherCpp(&tokenizer, &settings, this);
         checkOtherCpp.invalidPointerCast();
     }
 
diff --git a/test/testpostfixoperator.cpp b/test/testpostfixoperator.cpp
index 9e95fabc949..1d01217231a 100644
--- a/test/testpostfixoperator.cpp
+++ b/test/testpostfixoperator.cpp
@@ -38,8 +38,7 @@ class TestPostfixOperator : public TestFixture {
         SimpleTokenizer tokenizer(settings, *this);
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
-        // Check for postfix operators..
-        CheckPostfixOperator checkPostfixOperator(&tokenizer, &settings, this);
+        CheckPostfixOperatorImpl checkPostfixOperator(&tokenizer, &settings, this);
         checkPostfixOperator.postfixOperator();
     }
 
diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp
index 6fe563a57ca..6ad2047ddd7 100644
--- a/test/testuninitvar.cpp
+++ b/test/testuninitvar.cpp
@@ -127,7 +127,7 @@ class TestUninitVar : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check for redundant code..
-        CheckUninitVar checkuninitvar(&tokenizer, &settings1, this);
+        CheckUninitVarImpl checkuninitvar(&tokenizer, &settings1, this);
         checkuninitvar.check();
     }
 
@@ -137,7 +137,7 @@ class TestUninitVar : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check for redundant code..
-        CheckUninitVar checkuninitvar(&tokenizer, &settings, this);
+        CheckUninitVarImpl checkuninitvar(&tokenizer, &settings, this);
         checkuninitvar.check();
     }
 
@@ -3673,7 +3673,7 @@ class TestUninitVar : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check for redundant code..
-        CheckUninitVar checkuninitvar(&tokenizer, &settings, this);
+        CheckUninitVarImpl checkuninitvar(&tokenizer, &settings, this);
         (checkuninitvar.valueFlowUninit)();
     }
 
diff --git a/test/testunusedprivfunc.cpp b/test/testunusedprivfunc.cpp
index 5a364347163..3b419814dca 100644
--- a/test/testunusedprivfunc.cpp
+++ b/test/testunusedprivfunc.cpp
@@ -104,7 +104,7 @@ class TestUnusedPrivateFunction : public TestFixture {
         ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line);
 
         // Check for unused private functions..
-        CheckClass checkClass(&tokenizer, &settings1, this);
+        CheckClassImpl checkClass(&tokenizer, &settings1, this);
         checkClass.privateFunctions();
     }
 
diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp
index 13d288a3fdd..d0ad22b004d 100644
--- a/test/testunusedvar.cpp
+++ b/test/testunusedvar.cpp
@@ -290,7 +290,7 @@ class TestUnusedVar : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check for unused variables..
-        CheckUnusedVar checkUnusedVar(&tokenizer, &settings, this);
+        CheckUnusedVarImpl checkUnusedVar(&tokenizer, &settings, this);
         checkUnusedVar.checkFunctionVariableUsage();
     }
 
@@ -310,7 +310,7 @@ class TestUnusedVar : public TestFixture {
         ASSERT_LOC(tokenizer.tokenize(code), file, line);
 
         // Check for unused variables..
-        CheckUnusedVar checkUnusedVar(&tokenizer, &settings, this);
+        CheckUnusedVarImpl checkUnusedVar(&tokenizer, &settings, this);
         (checkUnusedVar.checkStructMemberUsage)();
     }
 
@@ -323,7 +323,7 @@ class TestUnusedVar : public TestFixture {
         ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line);
 
         // Check for unused variables..
-        CheckUnusedVar checkUnusedVar(&tokenizer, &settings, this);
+        CheckUnusedVarImpl checkUnusedVar(&tokenizer, &settings, this);
         (checkUnusedVar.checkStructMemberUsage)();
     }
 
@@ -336,7 +336,7 @@ class TestUnusedVar : public TestFixture {
         ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line);
 
         // Check for unused variables..
-        CheckUnusedVar checkUnusedVar(&tokenizer, &settings, this);
+        CheckUnusedVarImpl checkUnusedVar(&tokenizer, &settings, this);
         (checkUnusedVar.checkFunctionVariableUsage)();
     }
 
diff --git a/tools/dmake/dmake.cpp b/tools/dmake/dmake.cpp
index 80f3aa35b83..3d08943f5ba 100644
--- a/tools/dmake/dmake.cpp
+++ b/tools/dmake/dmake.cpp
@@ -495,6 +495,7 @@ int main(int argc, char **argv)
     }
     libfiles_h.emplace("analyzer.h");
     libfiles_h.emplace("calculate.h");
+    libfiles_h.emplace("check.h");
     libfiles_h.emplace("config.h");
     libfiles_h.emplace("filesettings.h");
     libfiles_h.emplace("findtoken.h");
@@ -559,7 +560,7 @@ int main(int argc, char **argv)
 
         for (const std::string &libfile: libfiles_prio) {
             const std::string l = libfile.substr(4);
-            outstr += make_vcxproj_cl_entry(l, l == "check.cpp" ? Precompile : Compile);
+            outstr += make_vcxproj_cl_entry(l, l == "checkimpl.cpp" ? Precompile : Compile);
         }
     }, [&](std::string &outstr){
         outstr += make_vcxproj_cl_entry(R"(..\externals\simplecpp\simplecpp.h)", Include);
