@@ -217,6 +217,52 @@ void CheckClass::constructors()
217217 }
218218}
219219
220+ void CheckClass::checkExplicitConstructors ()
221+ {
222+ if (!_settings->isEnabled (" performance" ))
223+ return ;
224+
225+ const std::size_t classes = symbolDatabase->classAndStructScopes .size ();
226+ for (std::size_t i = 0 ; i < classes; ++i) {
227+ const Scope * scope = symbolDatabase->classAndStructScopes [i];
228+
229+ // Do not perform check, if the class/struct has not any constructors
230+ if (scope->numConstructors == 0 )
231+ continue ;
232+
233+ // Is class abstract? Maybe this test is over-simplification, but it will suffice for simple cases,
234+ // and it will avoid false positives.
235+ bool isAbstractClass = false ;
236+ for (std::list<Function>::const_iterator func = scope->functionList .begin (); func != scope->functionList .end (); ++func) {
237+ if (func->isPure ()) {
238+ isAbstractClass = true ;
239+ break ;
240+ }
241+ }
242+
243+ for (std::list<Function>::const_iterator func = scope->functionList .begin (); func != scope->functionList .end (); ++func) {
244+
245+ // We are looking for constructors, which are meeting following criteria:
246+ // 1) Constructor is declared with a single parameter
247+ // 2) Constructor is not declared as explicit
248+ // 3) It is not a copy/move constructor of non-abstract class
249+ // 4) Constructor is not marked as delete (programmer can mark the default constructor as deleted, which is ok)
250+ if (!func->isConstructor () || func->isDelete ())
251+ continue ;
252+
253+ if (!func->isExplicit () && func->argCount () == 1 ) {
254+ // We must decide, if it is not a copy/move constructor, or it is a copy/move constructor of abstract class.
255+ if (func->type != Function::eCopyConstructor && func->type != Function::eMoveConstructor) {
256+ noExplicitConstructorError (func->tokenDef , scope->className , scope->type == Scope::eStruct);
257+ }
258+ else if (isAbstractClass) {
259+ noExplicitCopyMoveConstructorError (func->tokenDef , scope->className , scope->type == Scope::eStruct);
260+ }
261+ }
262+ }
263+ }
264+ }
265+
220266void CheckClass::copyconstructors ()
221267{
222268 if (!_settings->isEnabled (" style" ))
@@ -723,6 +769,16 @@ void CheckClass::noConstructorError(const Token *tok, const std::string &classna
723769 " instantiated. That may cause bugs or undefined behavior." );
724770}
725771
772+ void CheckClass::noExplicitConstructorError (const Token *tok, const std::string &classname, bool isStruct)
773+ {
774+ reportError (tok, Severity::performance, " noExplicitConstructor" , " The constructor of " + std::string (isStruct ? " struct" : " class" ) + " '" + classname + " ' should be marked as explicit. " );
775+ }
776+
777+ void CheckClass::noExplicitCopyMoveConstructorError (const Token *tok, const std::string &classname, bool isStruct)
778+ {
779+ reportError (tok, Severity::performance, " noExplicitCopyMoveConstructor" , " The copy/move constructor of abstract " + std::string (isStruct ? " struct" : " class" ) + " '" + classname + " ' should be marked as explicit. " );
780+ }
781+
726782void CheckClass::uninitVarError (const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive)
727783{
728784 reportError (tok, Severity::warning, " uninitMemberVar" , " Member variable '" + classname + " ::" + varname + " ' is not initialized in the constructor." , inconclusive);
0 commit comments