2010-11-13 08:08:45 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2022-02-05 11:45:17 +01:00
* Copyright ( C ) 2007 - 2022 Cppcheck team .
2010-11-13 08:08:45 +01:00
*
* 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/>.
*/
//---------------------------------------------------------------------------
# include "symboldatabase.h"
2019-03-30 10:32:36 +01:00
# include "astutils.h"
2010-11-13 08:08:45 +01:00
# include "errorlogger.h"
2022-01-27 19:03:20 +01:00
# include "errortypes.h"
2020-09-09 04:54:38 +02:00
# include "library.h"
2020-08-20 18:21:29 +02:00
# include "mathlib.h"
2022-06-15 21:25:55 +02:00
# include "path.h"
2017-05-27 04:33:47 +02:00
# include "platform.h"
# include "settings.h"
2022-01-27 19:03:20 +01:00
# include "standards.h"
# include "templatesimplifier.h"
2017-05-27 04:33:47 +02:00
# include "token.h"
# include "tokenize.h"
# include "tokenlist.h"
2015-11-29 10:49:10 +01:00
# include "utils.h"
2017-05-27 04:33:47 +02:00
# include "valueflow.h"
2010-11-13 08:08:45 +01:00
2017-05-27 04:33:47 +02:00
# include <algorithm>
2017-09-15 00:11:27 +02:00
# include <cassert>
2020-11-01 15:30:40 +01:00
# include <cstring>
2015-01-09 21:34:57 +01:00
# include <iomanip>
2017-05-27 04:33:47 +02:00
# include <iostream>
2021-06-04 17:15:39 +02:00
# include <limits>
2022-09-16 07:15:49 +02:00
# include <sstream> // IWYU pragma: keep
2022-01-27 19:03:20 +01:00
# include <stack>
2021-06-04 17:15:39 +02:00
# include <string>
2022-02-11 19:44:08 +01:00
# include <type_traits>
2020-08-20 18:21:29 +02:00
# include <unordered_map>
2022-01-27 19:03:20 +01:00
# include <unordered_set>
2010-11-13 08:08:45 +01:00
//---------------------------------------------------------------------------
SymbolDatabase : : SymbolDatabase ( const Tokenizer * tokenizer , const Settings * settings , ErrorLogger * errorLogger )
2018-06-16 16:10:28 +02:00
: mTokenizer ( tokenizer ) , mSettings ( settings ) , mErrorLogger ( errorLogger )
2017-01-01 11:34:05 +01:00
{
2020-01-05 15:12:53 +01:00
if ( ! tokenizer | | ! tokenizer - > tokens ( ) )
return ;
2018-06-16 23:30:00 +02:00
mIsCpp = isCPP ( ) ;
2017-03-22 02:55:22 +01:00
2018-06-16 16:10:28 +02:00
if ( mSettings - > defaultSign = = ' s ' | | mSettings - > defaultSign = = ' S ' )
2018-06-16 23:25:35 +02:00
mDefaultSignedness = ValueType : : SIGNED ;
2018-06-16 16:10:28 +02:00
else if ( mSettings - > defaultSign = = ' u ' | | mSettings - > defaultSign = = ' U ' )
2018-06-16 23:25:35 +02:00
mDefaultSignedness = ValueType : : UNSIGNED ;
2017-03-22 02:55:22 +01:00
else
2018-06-16 23:25:35 +02:00
mDefaultSignedness = ValueType : : UNKNOWN_SIGN ;
2017-03-22 02:55:22 +01:00
2017-01-01 11:34:05 +01:00
createSymbolDatabaseFindAllScopes ( ) ;
createSymbolDatabaseClassInfo ( ) ;
createSymbolDatabaseVariableInfo ( ) ;
2018-01-07 14:20:19 +01:00
createSymbolDatabaseCopyAndMoveConstructors ( ) ;
2017-01-01 11:34:05 +01:00
createSymbolDatabaseFunctionScopes ( ) ;
createSymbolDatabaseClassAndStructScopes ( ) ;
createSymbolDatabaseFunctionReturnTypes ( ) ;
createSymbolDatabaseNeedInitialization ( ) ;
createSymbolDatabaseVariableSymbolTable ( ) ;
createSymbolDatabaseSetScopePointers ( ) ;
createSymbolDatabaseSetVariablePointers ( ) ;
2019-08-05 13:42:00 +02:00
setValueTypeInTokenList ( false ) ;
2017-01-01 11:34:05 +01:00
createSymbolDatabaseSetTypePointers ( ) ;
2021-11-28 15:25:21 +01:00
createSymbolDatabaseSetFunctionPointers ( true ) ;
2021-11-29 07:06:43 +01:00
createSymbolDatabaseSetSmartPointerType ( ) ;
2021-11-28 15:25:21 +01:00
setValueTypeInTokenList ( false ) ;
2017-01-01 11:34:05 +01:00
createSymbolDatabaseEnums ( ) ;
2019-08-08 07:46:47 +02:00
createSymbolDatabaseEscapeFunctions ( ) ;
2019-08-05 07:18:06 +02:00
createSymbolDatabaseIncompleteVars ( ) ;
2020-08-20 18:21:29 +02:00
createSymbolDatabaseExprIds ( ) ;
2022-06-15 21:25:55 +02:00
debugSymbolDatabase ( ) ;
2017-01-01 11:34:05 +01:00
}
2018-05-01 07:32:19 +02:00
static const Token * skipScopeIdentifiers ( const Token * tok )
{
2021-05-01 07:35:03 +02:00
if ( Token : : Match ( tok , " :: %name% " ) )
2018-05-01 07:32:19 +02:00
tok = tok - > next ( ) ;
while ( Token : : Match ( tok , " %name% :: " ) | |
2021-05-01 07:35:03 +02:00
( Token : : Match ( tok , " %name% < " ) & & Token : : Match ( tok - > linkAt ( 1 ) , " >|>> :: " ) ) ) {
2018-05-01 07:32:19 +02:00
if ( tok - > strAt ( 1 ) = = " :: " )
tok = tok - > tokAt ( 2 ) ;
else
tok = tok - > linkAt ( 1 ) - > tokAt ( 2 ) ;
}
return tok ;
}
2019-04-15 06:37:27 +02:00
static bool isExecutableScope ( const Token * tok )
{
if ( ! Token : : simpleMatch ( tok , " { " ) )
return false ;
const Token * tok2 = tok - > link ( ) - > previous ( ) ;
if ( Token : : simpleMatch ( tok2 , " ; } " ) )
return true ;
2022-03-13 06:27:17 +01:00
if ( tok2 = = tok )
return false ;
if ( Token : : simpleMatch ( tok2 , " } } " ) ) { // inner scope
const Token * startTok = tok2 - > link ( ) ;
2019-04-15 06:37:27 +02:00
if ( Token : : Match ( startTok - > previous ( ) , " do|try|else { " ) )
return true ;
2022-03-13 06:27:17 +01:00
if ( Token : : Match ( startTok - > previous ( ) , " )|] { " ) )
2019-04-15 06:37:27 +02:00
return ! findLambdaStartToken ( tok2 ) ;
2022-03-13 06:27:17 +01:00
return isExecutableScope ( startTok ) ;
2019-04-15 06:37:27 +02:00
}
return false ;
}
2017-01-01 11:34:05 +01:00
void SymbolDatabase : : createSymbolDatabaseFindAllScopes ( )
2010-11-13 08:08:45 +01:00
{
2011-03-11 01:43:29 +01:00
// create global scope
2018-04-11 09:44:35 +02:00
scopeList . emplace_back ( this , nullptr , nullptr ) ;
2011-03-11 01:43:29 +01:00
// pointer to current scope
Scope * scope = & scopeList . back ( ) ;
2022-03-13 06:27:17 +01:00
// Store the ending of init lists
2022-01-15 07:56:56 +01:00
std : : stack < std : : pair < const Token * , const Scope * > > endInitList ;
auto inInitList = [ & ] {
if ( endInitList . empty ( ) )
return false ;
return endInitList . top ( ) . second = = scope ;
} ;
2012-04-18 13:00:34 +02:00
// Store current access in each scope (depends on evaluation progress)
std : : map < const Scope * , AccessControl > access ;
2011-03-11 01:43:29 +01:00
// find all scopes
2018-06-16 16:10:28 +02:00
for ( const Token * tok = mTokenizer - > tokens ( ) ; tok ; tok = tok ? tok - > next ( ) : nullptr ) {
2014-04-18 20:42:22 +02:00
// #5593 suggested to add here:
2018-06-16 16:10:28 +02:00
if ( mErrorLogger )
mErrorLogger - > reportProgress ( mTokenizer - > list . getSourceFilePath ( ) ,
2014-04-18 21:19:49 +02:00
" SymbolDatabase " ,
tok - > progressValue ( ) ) ;
2010-11-13 08:08:45 +01:00
// Locate next class
2020-05-17 17:32:31 +02:00
if ( ( mTokenizer - > isCPP ( ) & & tok - > isKeyword ( ) & &
2021-12-22 21:47:39 +01:00
( ( Token : : Match ( tok , " class|struct|union|namespace ::| %name% final| {|:|::|< " ) & &
2020-05-17 17:32:31 +02:00
! Token : : Match ( tok - > previous ( ) , " new|friend|const|enum|typedef|mutable|volatile|using|)|(|< " ) ) | |
( Token : : Match ( tok , " enum class| %name% { " ) | |
Token : : Match ( tok , " enum class| %name% : %name% { " ) ) ) )
| | ( mTokenizer - > isC ( ) & & tok - > isKeyword ( ) & & Token : : Match ( tok , " struct|union|enum %name% { " ) ) ) {
2012-11-30 06:03:58 +01:00
const Token * tok2 = tok - > tokAt ( 2 ) ;
2012-10-16 06:11:28 +02:00
2012-11-30 06:03:58 +01:00
if ( tok - > strAt ( 1 ) = = " :: " )
tok2 = tok2 - > next ( ) ;
2018-06-16 16:10:28 +02:00
else if ( mTokenizer - > isCPP ( ) & & tok - > strAt ( 1 ) = = " class " )
2016-04-22 06:02:54 +02:00
tok2 = tok2 - > next ( ) ;
2012-04-18 13:00:34 +02:00
2018-03-31 17:54:47 +02:00
while ( Token : : Match ( tok2 , " :: %name% " ) )
2012-11-30 06:03:58 +01:00
tok2 = tok2 - > tokAt ( 2 ) ;
2018-04-06 16:03:58 +02:00
while ( Token : : Match ( tok2 , " %name% :: %name% " ) )
tok2 = tok2 - > tokAt ( 2 ) ;
2012-11-30 06:03:58 +01:00
2015-01-19 16:15:11 +01:00
// skip over template args
2018-05-01 07:32:19 +02:00
while ( tok2 & & tok2 - > str ( ) = = " < " & & tok2 - > link ( ) ) {
2015-01-19 16:15:11 +01:00
tok2 = tok2 - > link ( ) - > next ( ) ;
2018-05-01 07:32:19 +02:00
while ( Token : : Match ( tok2 , " :: %name% " ) )
tok2 = tok2 - > tokAt ( 2 ) ;
}
2015-01-19 16:15:11 +01:00
2018-05-21 21:23:21 +02:00
// skip over final
2018-06-16 16:10:28 +02:00
if ( mTokenizer - > isCPP ( ) & & Token : : simpleMatch ( tok2 , " final " ) )
2018-05-21 21:23:21 +02:00
tok2 = tok2 - > next ( ) ;
2012-11-30 06:03:58 +01:00
// make sure we have valid code
2018-01-01 04:21:30 +01:00
if ( ! Token : : Match ( tok2 , " {|: " ) ) {
2013-03-28 06:36:49 +01:00
// check for qualified variable
if ( tok2 & & tok2 - > next ( ) ) {
if ( tok2 - > next ( ) - > str ( ) = = " ; " )
tok = tok2 - > next ( ) ;
2014-03-14 16:26:37 +01:00
else if ( Token : : simpleMatch ( tok2 - > next ( ) , " = { " ) &&
2015-05-23 23:18:59 +02:00
Token : : simpleMatch ( tok2 - > linkAt ( 2 ) , " } ; " ) )
2013-03-28 06:36:49 +01:00
tok = tok2 - > linkAt ( 2 ) - > next ( ) ;
2014-03-23 20:08:16 +01:00
else if ( Token : : Match ( tok2 - > next ( ) , " (| { " ) &&
tok2 - > next ( ) - > link ( ) - > strAt ( 1 ) = = " ; " )
2013-03-28 06:36:49 +01:00
tok = tok2 - > next ( ) - > link ( ) - > next ( ) ;
2015-01-19 06:38:54 +01:00
// skip variable declaration
2016-07-09 09:22:52 +02:00
else if ( Token : : Match ( tok2 , " *|&|> " ) )
2015-01-19 06:38:54 +01:00
continue ;
2018-06-16 16:10:28 +02:00
else if ( Token : : Match ( tok2 , " %name% ( " ) & & mTokenizer - > isFunctionHead ( tok2 - > next ( ) , " { ; " ))
2018-04-02 13:14:48 +02:00
continue ;
2022-03-14 17:59:29 +01:00
else if ( Token : : Match ( tok2 , " %name% [|= " ) )
2018-04-06 16:03:58 +02:00
continue ;
2018-04-08 07:29:19 +02:00
// skip template
2018-05-13 19:00:42 +02:00
else if ( Token : : simpleMatch ( tok2 , " ; " ) & &
Token : : Match ( tok - > previous ( ) , " template|> class|struct " ) ) {
2018-04-08 07:29:19 +02:00
tok = tok2 ;
continue ;
2018-05-13 19:00:42 +02:00
}
// forward declaration
else if ( Token : : simpleMatch ( tok2 , " ; " ) & &
Token : : Match ( tok , " class|struct|union " ) ) {
// TODO: see if it can be used
tok = tok2 ;
continue ;
}
// skip constructor
else if ( Token : : simpleMatch ( tok2 , " ( " ) & &
Token : : simpleMatch ( tok2 - > link ( ) , " ) ; " ) ) {
tok = tok2 - > link ( ) - > next ( ) ;
continue ;
2018-04-08 07:29:19 +02:00
} else
2018-04-02 13:14:48 +02:00
throw InternalError ( tok2 , " SymbolDatabase bailout; unhandled code " , InternalError : : SYNTAX ) ;
2013-03-28 06:36:49 +01:00
continue ;
}
break ; // bail
}
2012-11-30 06:03:58 +01:00
2018-05-04 07:56:20 +02:00
const Token * name = tok - > next ( ) ;
if ( name - > str ( ) = = " class " & & name - > strAt ( - 1 ) = = " enum " )
name = name - > next ( ) ;
Scope * new_scope = findScope ( name , scope ) ;
2012-10-16 19:12:27 +02:00
2012-11-30 06:03:58 +01:00
if ( new_scope ) {
// only create base list for classes and structures
if ( new_scope - > isClassOrStruct ( ) ) {
// goto initial '{'
2018-02-05 23:28:33 +01:00
if ( ! new_scope - > definedType )
2018-06-16 16:10:28 +02:00
mTokenizer - > syntaxError ( nullptr ) ; // #6808
2018-02-02 08:45:13 +01:00
tok2 = new_scope - > definedType - > initBaseInfo ( tok , tok2 ) ;
2012-11-30 06:03:58 +01:00
// make sure we have valid code
if ( ! tok2 ) {
break ;
}
}
2013-02-01 06:31:02 +01:00
// definition may be different than declaration
2018-06-16 16:10:28 +02:00
if ( mTokenizer - > isCPP ( ) & & tok - > str ( ) = = " class " ) {
2019-07-23 14:29:02 +02:00
access [ new_scope ] = AccessControl : : Private ;
2013-02-01 06:31:02 +01:00
new_scope - > type = Scope : : eClass ;
} else if ( tok - > str ( ) = = " struct " ) {
2019-07-23 14:29:02 +02:00
access [ new_scope ] = AccessControl : : Public ;
2013-02-01 06:31:02 +01:00
new_scope - > type = Scope : : eStruct ;
}
2012-11-30 06:03:58 +01:00
new_scope - > classDef = tok ;
2021-08-10 07:00:11 +02:00
new_scope - > setBodyStartEnd ( tok2 ) ;
2017-09-19 21:13:50 +02:00
// make sure we have valid code
2018-04-27 22:36:30 +02:00
if ( ! new_scope - > bodyEnd ) {
2018-06-16 16:10:28 +02:00
mTokenizer - > syntaxError ( tok ) ;
2017-09-19 21:13:50 +02:00
}
2012-11-30 06:03:58 +01:00
scope = new_scope ;
tok = tok2 ;
} else {
2018-04-11 09:44:35 +02:00
scopeList . emplace_back ( this , tok , scope ) ;
2012-11-30 06:03:58 +01:00
new_scope = & scopeList . back ( ) ;
if ( tok - > str ( ) = = " class " )
2019-07-23 14:29:02 +02:00
access [ new_scope ] = AccessControl : : Private ;
2017-10-15 11:49:36 +02:00
else if ( tok - > str ( ) = = " struct " | | tok - > str ( ) = = " union " )
2019-07-23 14:29:02 +02:00
access [ new_scope ] = AccessControl : : Public ;
2012-11-30 06:03:58 +01:00
2013-03-05 15:28:40 +01:00
// fill typeList...
2017-10-15 11:49:36 +02:00
if ( new_scope - > isClassOrStructOrUnion ( ) | | new_scope - > type = = Scope : : eEnum ) {
2018-05-04 07:56:20 +02:00
Type * new_type = findType ( name , scope ) ;
2013-03-05 15:28:40 +01:00
if ( ! new_type ) {
2018-04-11 09:44:35 +02:00
typeList . emplace_back ( new_scope - > classDef , new_scope , scope ) ;
2013-03-05 15:28:40 +01:00
new_type = & typeList . back ( ) ;
2017-10-15 02:53:41 +02:00
scope - > definedTypesMap [ new_type - > name ( ) ] = new_type ;
2013-03-05 15:28:40 +01:00
} else
new_type - > classScope = new_scope ;
new_scope - > definedType = new_type ;
}
2012-11-30 06:03:58 +01:00
// only create base list for classes and structures
if ( new_scope - > isClassOrStruct ( ) ) {
// goto initial '{'
2013-03-05 15:28:40 +01:00
tok2 = new_scope - > definedType - > initBaseInfo ( tok , tok2 ) ;
2012-11-30 06:03:58 +01:00
// make sure we have valid code
if ( ! tok2 ) {
2018-06-16 16:10:28 +02:00
mTokenizer - > syntaxError ( tok ) ;
2012-11-30 06:03:58 +01:00
}
2016-04-22 06:02:54 +02:00
} else if ( new_scope - > type = = Scope : : eEnum ) {
if ( tok2 - > str ( ) = = " : " )
tok2 = tok2 - > tokAt ( 2 ) ;
2012-11-30 06:03:58 +01:00
}
2021-08-10 07:00:11 +02:00
new_scope - > setBodyStartEnd ( tok2 ) ;
2011-02-19 20:38:00 +01:00
// make sure we have valid code
2018-04-27 22:36:30 +02:00
if ( ! new_scope - > bodyEnd ) {
2018-06-16 16:10:28 +02:00
mTokenizer - > syntaxError ( tok ) ;
2011-02-19 20:38:00 +01:00
}
2010-11-13 08:08:45 +01:00
2016-04-22 06:02:54 +02:00
if ( new_scope - > type = = Scope : : eEnum ) {
2018-06-16 16:10:28 +02:00
tok2 = new_scope - > addEnum ( tok , mTokenizer - > isCPP ( ) ) ;
2016-04-22 06:02:54 +02:00
scope - > nestedList . push_back ( new_scope ) ;
if ( ! tok2 )
2018-06-16 16:10:28 +02:00
mTokenizer - > syntaxError ( tok ) ;
2016-04-22 06:02:54 +02:00
} else {
// make the new scope the current scope
scope - > nestedList . push_back ( new_scope ) ;
scope = new_scope ;
}
2010-12-16 19:04:47 +01:00
2012-11-30 06:03:58 +01:00
tok = tok2 ;
}
2012-06-05 06:37:55 +02:00
}
// Namespace and unknown macro (#3854)
2020-05-17 17:32:31 +02:00
else if ( mTokenizer - > isCPP ( ) & & tok - > isKeyword ( ) & &
2015-01-31 10:50:39 +01:00
Token : : Match ( tok , " namespace %name% %type% ( " ) & &
2012-06-21 19:00:53 +02:00
tok - > tokAt ( 2 ) - > isUpperCaseName ( ) & &
2012-06-05 06:37:55 +02:00
Token : : simpleMatch ( tok - > linkAt ( 3 ) , " ) { " ) ) {
2018-04-11 09:44:35 +02:00
scopeList . emplace_back ( this , tok , scope ) ;
2012-06-05 06:37:55 +02:00
Scope * new_scope = & scopeList . back ( ) ;
2019-07-23 14:29:02 +02:00
access [ new_scope ] = AccessControl : : Public ;
2012-06-05 06:37:55 +02:00
const Token * tok2 = tok - > linkAt ( 3 ) - > next ( ) ;
2021-08-10 07:00:11 +02:00
new_scope - > setBodyStartEnd ( tok2 ) ;
2012-06-05 06:37:55 +02:00
// make sure we have valid code
2018-04-27 22:36:30 +02:00
if ( ! new_scope - > bodyEnd ) {
2012-06-05 06:37:55 +02:00
scopeList . pop_back ( ) ;
break ;
}
// make the new scope the current scope
2013-03-05 18:42:42 +01:00
scope - > nestedList . push_back ( new_scope ) ;
2012-06-05 06:37:55 +02:00
scope = & scopeList . back ( ) ;
2010-11-13 08:08:45 +01:00
tok = tok2 ;
}
2011-01-20 18:02:52 +01:00
// forward declaration
2020-05-17 17:32:31 +02:00
else if ( tok - > isKeyword ( ) & & Token : : Match ( tok , " class|struct|union %name% ; " ) &&
2012-11-30 06:03:58 +01:00
tok - > strAt ( - 1 ) ! = " friend " ) {
2013-03-05 13:33:38 +01:00
if ( ! findType ( tok - > next ( ) , scope ) ) {
// fill typeList..
2018-04-11 09:44:35 +02:00
typeList . emplace_back ( tok , nullptr , scope ) ;
2017-10-15 02:53:41 +02:00
Type * new_type = & typeList . back ( ) ;
scope - > definedTypesMap [ new_type - > name ( ) ] = new_type ;
2012-11-30 06:03:58 +01:00
}
2011-01-20 18:02:52 +01:00
tok = tok - > tokAt ( 2 ) ;
}
2011-03-14 02:01:33 +01:00
// using namespace
2020-05-17 17:32:31 +02:00
else if ( mTokenizer - > isCPP ( ) & & tok - > isKeyword ( ) & & Token : : Match ( tok , " using namespace ::| %type% ; | : : " )) {
2012-12-20 06:53:04 +01:00
Scope : : UsingInfo using_info ;
using_info . start = tok ; // save location
2014-04-10 16:11:11 +02:00
using_info . scope = findNamespace ( tok - > tokAt ( 2 ) , scope ) ;
2012-12-20 06:53:04 +01:00
scope - > usingList . push_back ( using_info ) ;
2011-03-14 02:01:33 +01:00
2013-02-14 06:31:41 +01:00
// check for global namespace
if ( tok - > strAt ( 2 ) = = " :: " )
tok = tok - > tokAt ( 4 ) ;
else
tok = tok - > tokAt ( 3 ) ;
// skip over qualification
2016-11-26 17:08:36 +01:00
while ( Token : : Match ( tok , " %type% :: " ) )
2013-02-14 06:31:41 +01:00
tok = tok - > tokAt ( 2 ) ;
2011-03-14 02:01:33 +01:00
}
2018-01-10 22:16:18 +01:00
// using type alias
2020-05-17 17:32:31 +02:00
else if ( mTokenizer - > isCPP ( ) & & tok - > isKeyword ( ) & & Token : : Match ( tok , " using %name% = " ) ) {
2018-01-21 21:22:26 +01:00
if ( tok - > strAt ( - 1 ) ! = " > " & & ! findType ( tok - > next ( ) , scope ) ) {
2018-01-10 22:16:18 +01:00
// fill typeList..
2018-04-11 09:44:35 +02:00
typeList . emplace_back ( tok , nullptr , scope ) ;
2018-01-10 22:16:18 +01:00
Type * new_type = & typeList . back ( ) ;
scope - > definedTypesMap [ new_type - > name ( ) ] = new_type ;
}
tok = tok - > tokAt ( 3 ) ;
while ( tok & & tok - > str ( ) ! = " ; " )
tok = tok - > next ( ) ;
}
2011-03-30 01:48:12 +02:00
// unnamed struct and union
2020-05-17 17:32:31 +02:00
else if ( tok - > isKeyword ( ) & & Token : : Match ( tok , " struct|union { " ) &&
2018-10-20 09:43:08 +02:00
Token : : Match ( tok - > next ( ) - > link ( ) , " } *|&| %name% ;|[|= " ) ) {
2018-04-11 09:44:35 +02:00
scopeList . emplace_back ( this , tok , scope ) ;
2011-03-27 19:48:41 +02:00
Scope * new_scope = & scopeList . back ( ) ;
2019-07-23 14:29:02 +02:00
access [ new_scope ] = AccessControl : : Public ;
2011-03-27 19:48:41 +02:00
2011-12-17 19:04:03 +01:00
const Token * varNameTok = tok - > next ( ) - > link ( ) - > next ( ) ;
if ( varNameTok - > str ( ) = = " * " ) {
varNameTok = varNameTok - > next ( ) ;
2012-01-26 17:04:25 +01:00
} else if ( varNameTok - > str ( ) = = " & " ) {
varNameTok = varNameTok - > next ( ) ;
2011-12-17 19:04:03 +01:00
}
2018-04-11 09:44:35 +02:00
typeList . emplace_back ( tok , new_scope , scope ) ;
2017-10-15 02:53:41 +02:00
{
2017-10-17 10:59:23 +02:00
Type * new_type = & typeList . back ( ) ;
new_scope - > definedType = new_type ;
scope - > definedTypesMap [ new_type - > name ( ) ] = new_type ;
2017-10-15 02:53:41 +02:00
}
2013-03-05 13:33:38 +01:00
2018-06-20 10:00:15 +02:00
scope - > addVariable ( varNameTok , tok , tok , access [ scope ] , new_scope - > definedType , scope , mSettings ) ;
2011-03-27 19:48:41 +02:00
const Token * tok2 = tok - > next ( ) ;
2021-08-10 07:00:11 +02:00
new_scope - > setBodyStartEnd ( tok2 ) ;
2011-03-27 19:48:41 +02:00
// make sure we have valid code
2018-04-27 22:36:30 +02:00
if ( ! new_scope - > bodyEnd ) {
2011-03-27 19:48:41 +02:00
scopeList . pop_back ( ) ;
break ;
}
// make the new scope the current scope
2013-03-05 18:42:42 +01:00
scope - > nestedList . push_back ( new_scope ) ;
2013-03-05 13:33:38 +01:00
scope = new_scope ;
2011-03-27 19:48:41 +02:00
tok = tok2 ;
}
2014-09-24 06:09:08 +02:00
// anonymous struct, union and namespace
2020-05-17 17:32:31 +02:00
else if ( tok - > isKeyword ( ) & & ( ( Token : : Match ( tok , " struct|union { " ) &&
Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " } ; " ) ) | |
Token : : simpleMatch ( tok , " namespace { " ) ) ) {
2018-04-11 09:44:35 +02:00
scopeList . emplace_back ( this , tok , scope ) ;
2011-04-01 02:54:23 +02:00
Scope * new_scope = & scopeList . back ( ) ;
2019-07-23 14:29:02 +02:00
access [ new_scope ] = AccessControl : : Public ;
2011-04-01 02:54:23 +02:00
const Token * tok2 = tok - > next ( ) ;
2021-08-10 07:00:11 +02:00
new_scope - > setBodyStartEnd ( tok2 ) ;
2011-04-01 02:54:23 +02:00
2018-04-11 09:44:35 +02:00
typeList . emplace_back ( tok , new_scope , scope ) ;
2017-10-15 02:53:41 +02:00
{
2017-10-17 10:59:23 +02:00
Type * new_type = & typeList . back ( ) ;
new_scope - > definedType = new_type ;
scope - > definedTypesMap [ new_type - > name ( ) ] = new_type ;
2017-10-15 02:53:41 +02:00
}
2013-03-05 13:33:38 +01:00
2011-04-01 02:54:23 +02:00
// make sure we have valid code
2018-04-27 22:36:30 +02:00
if ( ! new_scope - > bodyEnd ) {
2011-04-01 02:54:23 +02:00
scopeList . pop_back ( ) ;
break ;
}
// make the new scope the current scope
2013-03-05 18:42:42 +01:00
scope - > nestedList . push_back ( new_scope ) ;
2013-03-05 13:33:38 +01:00
scope = new_scope ;
2011-04-01 02:54:23 +02:00
tok = tok2 ;
}
2016-04-22 06:02:54 +02:00
// forward declared enum
2020-05-17 17:32:31 +02:00
else if ( tok - > isKeyword ( ) & & ( Token : : Match ( tok , " enum class| %name% ; " ) || Token::Match(tok, " enum class | % name % : % name % ; " ))) {
2018-04-11 09:44:35 +02:00
typeList . emplace_back ( tok , nullptr , scope ) ;
2017-10-15 02:53:41 +02:00
Type * new_type = & typeList . back ( ) ;
scope - > definedTypesMap [ new_type - > name ( ) ] = new_type ;
2016-04-22 06:02:54 +02:00
tok = tok - > tokAt ( 2 ) ;
}
2017-01-09 22:48:05 +01:00
// check for end of scope
2018-04-27 22:36:30 +02:00
else if ( tok = = scope - > bodyEnd ) {
2017-01-09 22:48:05 +01:00
access . erase ( scope ) ;
scope = const_cast < Scope * > ( scope - > nestedIn ) ;
continue ;
}
2022-01-15 07:56:56 +01:00
// check for end of init list
else if ( inInitList ( ) & & tok = = endInitList . top ( ) . first ) {
endInitList . pop ( ) ;
continue ;
}
2010-11-13 08:08:45 +01:00
2017-10-15 11:49:36 +02:00
// check if in class or structure or union
else if ( scope - > isClassOrStructOrUnion ( ) ) {
2017-01-09 22:48:05 +01:00
const Token * funcStart = nullptr ;
const Token * argStart = nullptr ;
const Token * declEnd = nullptr ;
// What section are we in..
if ( tok - > str ( ) = = " private: " )
2019-07-23 14:29:02 +02:00
access [ scope ] = AccessControl : : Private ;
2017-01-09 22:48:05 +01:00
else if ( tok - > str ( ) = = " protected: " )
2019-07-23 14:29:02 +02:00
access [ scope ] = AccessControl : : Protected ;
2017-01-09 22:48:05 +01:00
else if ( tok - > str ( ) = = " public: " | | tok - > str ( ) = = " __published: " )
2019-07-23 14:29:02 +02:00
access [ scope ] = AccessControl : : Public ;
2017-01-09 22:48:05 +01:00
else if ( Token : : Match ( tok , " public|protected|private %name% : " ) ) {
if ( tok - > str ( ) = = " private " )
2019-07-23 14:29:02 +02:00
access [ scope ] = AccessControl : : Private ;
2017-01-09 22:48:05 +01:00
else if ( tok - > str ( ) = = " protected " )
2019-07-23 14:29:02 +02:00
access [ scope ] = AccessControl : : Protected ;
2017-01-09 22:48:05 +01:00
else
2019-07-23 14:29:02 +02:00
access [ scope ] = AccessControl : : Public ;
2010-11-13 08:08:45 +01:00
2017-01-09 22:48:05 +01:00
tok = tok - > tokAt ( 2 ) ;
}
2010-11-13 08:08:45 +01:00
2017-01-09 22:48:05 +01:00
// class function?
else if ( isFunction ( tok , scope , & funcStart , & argStart , & declEnd ) ) {
if ( tok - > previous ( ) - > str ( ) ! = " :: " | | tok - > strAt ( - 2 ) = = scope - > className ) {
2018-06-16 16:10:28 +02:00
Function function ( mTokenizer , tok , scope , funcStart , argStart ) ;
2010-11-13 08:08:45 +01:00
2017-01-09 22:48:05 +01:00
// save the access type
function . access = access [ scope ] ;
2010-11-13 08:08:45 +01:00
2017-01-09 22:48:05 +01:00
const Token * end = function . argDef - > link ( ) ;
// count the number of constructors
if ( function . isConstructor ( ) )
scope - > numConstructors + + ;
// assume implementation is inline (definition and implementation same)
function . token = function . tokenDef ;
function . arg = function . argDef ;
// out of line function
2018-06-16 16:10:28 +02:00
if ( const Token * endTok = mTokenizer - > isFunctionHead ( end , " ; " ) ) {
2018-04-25 12:05:49 +02:00
tok = endTok ;
2017-01-09 22:48:05 +01:00
scope - > addFunction ( function ) ;
}
2013-11-25 03:43:39 +01:00
2017-01-09 22:48:05 +01:00
// inline function
else {
// find start of function '{'
bool foundInitList = false ;
while ( end & & end - > str ( ) ! = " { " & & end - > str ( ) ! = " ; " ) {
if ( end - > link ( ) & & Token : : Match ( end , " (|< " ) ) {
end = end - > link ( ) ;
} else if ( foundInitList & &
Token : : Match ( end , " %name%|> { " ) & &
Token : : Match ( end - > linkAt ( 1 ) , " } ,|{ " ) ) {
end = end - > linkAt ( 1 ) ;
} else {
if ( end - > str ( ) = = " : " )
foundInitList = true ;
end = end - > next ( ) ;
2015-04-06 19:47:21 +02:00
}
2017-01-09 22:48:05 +01:00
}
2015-04-06 19:47:21 +02:00
2017-01-09 22:48:05 +01:00
if ( ! end | | end - > str ( ) = = " ; " )
continue ;
2011-02-20 14:25:42 +01:00
2017-01-09 22:48:05 +01:00
scope - > addFunction ( function ) ;
2010-11-13 08:08:45 +01:00
2017-01-09 22:48:05 +01:00
Function * funcptr = & scope - > functionList . back ( ) ;
const Token * tok2 = funcStart ;
2010-11-13 08:08:45 +01:00
2017-01-09 22:48:05 +01:00
addNewFunction ( & scope , & tok2 ) ;
if ( scope ) {
scope - > functionOf = function . nestedIn ;
scope - > function = funcptr ;
scope - > function - > functionScope = scope ;
2011-03-14 02:18:49 +01:00
}
2014-03-30 11:06:44 +02:00
2017-01-09 22:48:05 +01:00
tok = tok2 ;
2011-02-03 07:57:10 +01:00
}
}
2010-11-13 08:08:45 +01:00
2017-01-09 22:48:05 +01:00
// nested class or friend function?
else {
/** @todo check entire qualification for match */
2018-09-23 20:24:51 +02:00
const Scope * const nested = scope - > findInNestedListRecursive ( tok - > strAt ( - 2 ) ) ;
2010-11-13 08:08:45 +01:00
2017-01-09 22:48:05 +01:00
if ( nested )
addClassFunction ( & scope , & tok , argStart ) ;
else {
/** @todo handle friend functions */
}
}
}
2012-12-05 20:31:17 +01:00
2017-01-09 22:48:05 +01:00
// friend class declaration?
2022-04-13 14:49:28 +02:00
else if ( mTokenizer - > isCPP ( ) & & tok - > isKeyword ( ) & & Token : : Match ( tok , " friend class|struct| ::| %any% ; | : : " )) {
2017-01-09 22:48:05 +01:00
Type : : FriendInfo friendInfo ;
2012-12-05 20:31:17 +01:00
2017-01-09 22:48:05 +01:00
// save the name start
friendInfo . nameStart = tok - > strAt ( 1 ) = = " class " ? tok - > tokAt ( 2 ) : tok - > next ( ) ;
friendInfo . nameEnd = friendInfo . nameStart ;
2012-12-05 20:31:17 +01:00
2017-01-09 22:48:05 +01:00
// skip leading "::"
if ( friendInfo . nameEnd - > str ( ) = = " :: " )
friendInfo . nameEnd = friendInfo . nameEnd - > next ( ) ;
2012-12-05 20:31:17 +01:00
2017-01-09 22:48:05 +01:00
// skip qualification "name ::"
while ( friendInfo . nameEnd & & friendInfo . nameEnd - > strAt ( 1 ) = = " :: " )
friendInfo . nameEnd = friendInfo . nameEnd - > tokAt ( 2 ) ;
2010-11-13 08:08:45 +01:00
2017-01-09 22:48:05 +01:00
// fill this in after parsing is complete
2017-08-09 20:00:26 +02:00
friendInfo . type = nullptr ;
2014-04-20 20:40:55 +02:00
2017-01-09 22:48:05 +01:00
if ( ! scope - > definedType )
2018-06-16 16:10:28 +02:00
mTokenizer - > syntaxError ( tok ) ;
2014-04-10 16:17:10 +02:00
2017-01-09 22:48:05 +01:00
scope - > definedType - > friendList . push_back ( friendInfo ) ;
}
} else if ( scope - > type = = Scope : : eNamespace | | scope - > type = = Scope : : eGlobal ) {
const Token * funcStart = nullptr ;
const Token * argStart = nullptr ;
const Token * declEnd = nullptr ;
// function?
if ( isFunction ( tok , scope , & funcStart , & argStart , & declEnd ) ) {
// has body?
if ( declEnd & & declEnd - > str ( ) = = " { " ) {
tok = funcStart ;
// class function
if ( tok - > previous ( ) & & tok - > previous ( ) - > str ( ) = = " :: " )
addClassFunction ( & scope , & tok , argStart ) ;
// class destructor
else if ( tok - > previous ( ) & &
tok - > previous ( ) - > str ( ) = = " ~ " & &
tok - > strAt ( - 2 ) = = " :: " )
addClassFunction ( & scope , & tok , argStart ) ;
// regular function
else {
2018-09-23 20:24:51 +02:00
const Function * const function = addGlobalFunction ( scope , tok , argStart , funcStart ) ;
2014-04-10 16:17:10 +02:00
2017-01-09 22:48:05 +01:00
if ( ! function )
2018-06-16 16:10:28 +02:00
mTokenizer - > syntaxError ( tok ) ;
2017-01-09 22:48:05 +01:00
}
2013-08-31 18:58:55 +02:00
2017-01-09 22:48:05 +01:00
// syntax error?
if ( ! scope )
2018-06-16 16:10:28 +02:00
mTokenizer - > syntaxError ( tok ) ;
2017-01-09 22:48:05 +01:00
}
// function prototype?
else if ( declEnd & & declEnd - > str ( ) = = " ; " ) {
2022-02-02 19:30:49 +01:00
if ( tok - > astParent ( ) & & tok - > astParent ( ) - > str ( ) = = " :: " & &
2019-10-06 07:21:12 +02:00
Token : : Match ( declEnd - > previous ( ) , " default|delete " ) ) {
addClassFunction ( & scope , & tok , argStart ) ;
continue ;
}
2017-01-09 22:48:05 +01:00
bool newFunc = true ; // Is this function already in the database?
2022-06-08 16:58:57 +02:00
auto range = scope - > functionMap . equal_range ( tok - > str ( ) ) ;
for ( std : : multimap < std : : string , const Function * > : : const_iterator it = range . first ; it ! = range . second ; + + it ) {
if ( it - > second - > argsMatch ( scope , it - > second - > argDef , argStart , emptyString , 0 ) ) {
2017-01-09 22:48:05 +01:00
newFunc = false ;
break ;
}
}
2014-04-10 16:17:10 +02:00
2017-01-09 22:48:05 +01:00
// save function prototype in database
if ( newFunc ) {
2018-04-25 12:05:49 +02:00
addGlobalFunctionDecl ( scope , tok , argStart , funcStart ) ;
2011-03-14 03:59:25 +01:00
}
2017-01-09 22:48:05 +01:00
tok = declEnd ;
continue ;
2010-11-20 07:26:50 +01:00
}
2017-01-09 22:48:05 +01:00
}
} else if ( scope - > isExecutable ( ) ) {
2020-05-17 17:32:31 +02:00
if ( tok - > isKeyword ( ) & & Token : : Match ( tok , " else|try|do { " ) ) {
2017-01-09 22:48:05 +01:00
const Token * tok1 = tok - > next ( ) ;
if ( tok - > str ( ) = = " else " )
2018-04-11 09:44:35 +02:00
scopeList . emplace_back ( this , tok , scope , Scope : : eElse , tok1 ) ;
2017-04-30 08:58:41 +02:00
else if ( tok - > str ( ) = = " do " )
2018-04-11 09:44:35 +02:00
scopeList . emplace_back ( this , tok , scope , Scope : : eDo , tok1 ) ;
2017-01-09 22:48:05 +01:00
else //if (tok->str() == "try")
2018-04-11 09:44:35 +02:00
scopeList . emplace_back ( this , tok , scope , Scope : : eTry , tok1 ) ;
2017-01-09 22:48:05 +01:00
tok = tok1 ;
scope - > nestedList . push_back ( & scopeList . back ( ) ) ;
scope = & scopeList . back ( ) ;
2020-05-17 17:32:31 +02:00
} else if ( tok - > isKeyword ( ) & & Token : : Match ( tok , " if|for|while|catch|switch ( " ) & & Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " ) { " )) {
2017-01-09 22:48:05 +01:00
const Token * scopeStartTok = tok - > next ( ) - > link ( ) - > next ( ) ;
if ( tok - > str ( ) = = " if " )
2018-04-11 09:44:35 +02:00
scopeList . emplace_back ( this , tok , scope , Scope : : eIf , scopeStartTok ) ;
2017-01-09 22:48:05 +01:00
else if ( tok - > str ( ) = = " for " ) {
2018-04-11 09:44:35 +02:00
scopeList . emplace_back ( this , tok , scope , Scope : : eFor , scopeStartTok ) ;
2017-01-09 22:48:05 +01:00
} else if ( tok - > str ( ) = = " while " )
2018-04-11 09:44:35 +02:00
scopeList . emplace_back ( this , tok , scope , Scope : : eWhile , scopeStartTok ) ;
2017-01-09 22:48:05 +01:00
else if ( tok - > str ( ) = = " catch " ) {
2018-04-11 09:44:35 +02:00
scopeList . emplace_back ( this , tok , scope , Scope : : eCatch , scopeStartTok ) ;
2017-01-09 22:48:05 +01:00
} else // if (tok->str() == "switch")
2018-04-11 09:44:35 +02:00
scopeList . emplace_back ( this , tok , scope , Scope : : eSwitch , scopeStartTok ) ;
2017-01-09 22:48:05 +01:00
scope - > nestedList . push_back ( & scopeList . back ( ) ) ;
scope = & scopeList . back ( ) ;
if ( scope - > type = = Scope : : eFor )
2019-07-23 14:29:02 +02:00
scope - > checkVariable ( tok - > tokAt ( 2 ) , AccessControl : : Local , mSettings ) ; // check for variable declaration and add it to new scope if found
2017-01-09 22:48:05 +01:00
else if ( scope - > type = = Scope : : eCatch )
2019-07-23 14:29:02 +02:00
scope - > checkVariable ( tok - > tokAt ( 2 ) , AccessControl : : Throw , mSettings ) ; // check for variable declaration and add it to new scope if found
2017-01-09 22:48:05 +01:00
tok = scopeStartTok ;
2019-03-30 10:32:36 +01:00
} else if ( Token : : Match ( tok , " %var% { " ) ) {
2022-08-17 09:50:14 +02:00
endInitList . emplace ( tok - > next ( ) - > link ( ) , scope ) ;
2022-01-15 07:56:56 +01:00
tok = tok - > next ( ) ;
2019-03-30 10:32:36 +01:00
} else if ( const Token * lambdaEndToken = findLambdaEndToken ( tok ) ) {
const Token * lambdaStartToken = lambdaEndToken - > link ( ) ;
2019-07-05 12:30:42 +02:00
const Token * argStart = lambdaStartToken - > astParent ( ) ;
const Token * funcStart = Token : : simpleMatch ( argStart , " [ " ) ? argStart : argStart - > astParent ( ) ;
2019-07-06 10:46:17 +02:00
const Function * function = addGlobalFunction ( scope , tok , argStart , funcStart ) ;
if ( ! function )
mTokenizer - > syntaxError ( tok ) ;
2019-03-30 10:32:36 +01:00
tok = lambdaStartToken ;
2017-01-09 22:48:05 +01:00
} else if ( tok - > str ( ) = = " { " ) {
2022-01-15 07:56:56 +01:00
if ( inInitList ( ) ) {
2022-08-17 09:50:14 +02:00
endInitList . emplace ( tok - > link ( ) , scope ) ;
2022-01-15 07:56:56 +01:00
} else if ( isExecutableScope ( tok ) ) {
2019-03-30 10:32:36 +01:00
scopeList . emplace_back ( this , tok , scope , Scope : : eUnconditional , tok ) ;
scope - > nestedList . push_back ( & scopeList . back ( ) ) ;
scope = & scopeList . back ( ) ;
2022-01-15 07:56:56 +01:00
} else if ( scope - > isExecutable ( ) ) {
2022-08-17 09:50:14 +02:00
endInitList . emplace ( tok - > link ( ) , scope ) ;
2019-03-30 10:32:36 +01:00
} else {
2017-01-09 22:48:05 +01:00
tok = tok - > link ( ) ;
2011-02-26 21:53:57 +01:00
}
}
2019-07-06 10:46:17 +02:00
// syntax error?
if ( ! scope )
mTokenizer - > syntaxError ( tok ) ;
2022-01-26 06:28:13 +01:00
// End of scope or list should be handled above
if ( tok - > str ( ) = = " } " )
mTokenizer - > syntaxError ( tok ) ;
2010-11-20 07:26:50 +01:00
}
2010-11-13 08:08:45 +01:00
}
2017-01-01 11:34:05 +01:00
}
2010-11-13 08:08:45 +01:00
2017-01-01 11:34:05 +01:00
void SymbolDatabase : : createSymbolDatabaseClassInfo ( )
{
2018-06-16 16:10:28 +02:00
if ( mTokenizer - > isC ( ) )
2018-04-04 10:50:10 +02:00
return ;
// fill in using info
2020-09-21 19:30:47 +02:00
for ( Scope & scope : scopeList ) {
for ( Scope : : UsingInfo & usingInfo : scope . usingList ) {
2018-04-04 10:50:10 +02:00
// only find if not already found
2020-09-21 19:30:47 +02:00
if ( usingInfo . scope = = nullptr ) {
2018-04-04 10:50:10 +02:00
// check scope for match
2020-09-21 19:30:47 +02:00
const Scope * const found = findScope ( usingInfo . start - > tokAt ( 2 ) , & scope ) ;
if ( found ) {
2018-04-04 10:50:10 +02:00
// set found scope
2020-09-21 19:48:04 +02:00
usingInfo . scope = found ;
2018-04-04 10:50:10 +02:00
break ;
2017-07-16 01:14:15 +02:00
}
}
}
2018-04-04 10:50:10 +02:00
}
2017-07-16 01:14:15 +02:00
2018-04-04 10:50:10 +02:00
// fill in base class info
2020-09-21 19:30:47 +02:00
for ( Type & type : typeList ) {
2018-04-04 10:50:10 +02:00
// finish filling in base class info
2021-08-04 22:30:39 +02:00
for ( Type : : BaseInfo & i : type . derivedFrom ) {
2022-02-12 08:19:07 +01:00
const Type * found = findType ( i . nameTok , type . enclosingScope , /*lookOutside*/ true ) ;
2021-08-04 22:30:39 +02:00
if ( found & & found - > findDependency ( & type ) ) {
// circular dependency
//mTokenizer->syntaxError(nullptr);
} else {
i . type = found ;
2015-07-01 07:50:13 +02:00
}
2014-09-01 17:01:05 +02:00
}
2018-04-04 10:50:10 +02:00
}
2010-11-13 08:08:45 +01:00
2018-04-04 10:50:10 +02:00
// fill in friend info
2020-09-21 19:30:47 +02:00
for ( Type & type : typeList ) {
for ( Type : : FriendInfo & friendInfo : type . friendList ) {
friendInfo . type = findType ( friendInfo . nameStart , type . enclosingScope ) ;
2012-02-24 20:45:56 +01:00
}
2012-12-20 06:53:04 +01:00
}
2017-01-01 11:34:05 +01:00
}
2012-12-20 06:53:04 +01:00
2017-01-01 11:34:05 +01:00
void SymbolDatabase : : createSymbolDatabaseVariableInfo ( )
{
2010-12-02 07:35:01 +01:00
// fill in variable info
2020-09-21 19:30:47 +02:00
for ( Scope & scope : scopeList ) {
2011-02-26 21:57:16 +01:00
// find variables
2020-09-21 19:48:04 +02:00
scope . getVariableList ( mSettings ) ;
2010-12-02 07:35:01 +01:00
}
2011-02-26 21:51:12 +01:00
// fill in function arguments
2020-09-21 19:30:47 +02:00
for ( Scope & scope : scopeList ) {
2011-02-26 21:51:12 +01:00
std : : list < Function > : : iterator func ;
2020-09-21 19:30:47 +02:00
for ( func = scope . functionList . begin ( ) ; func ! = scope . functionList . end ( ) ; + + func ) {
2011-02-26 21:51:12 +01:00
// add arguments
2020-09-21 19:30:47 +02:00
func - > addArguments ( this , & scope ) ;
2011-02-26 21:51:12 +01:00
}
}
2017-01-01 11:34:05 +01:00
}
2011-02-26 21:51:12 +01:00
2018-01-07 14:20:19 +01:00
void SymbolDatabase : : createSymbolDatabaseCopyAndMoveConstructors ( )
{
// fill in class and struct copy/move constructors
2020-09-21 19:30:47 +02:00
for ( Scope & scope : scopeList ) {
if ( ! scope . isClassOrStruct ( ) )
2018-01-07 14:20:19 +01:00
continue ;
std : : list < Function > : : iterator func ;
2020-09-21 19:30:47 +02:00
for ( func = scope . functionList . begin ( ) ; func ! = scope . functionList . end ( ) ; + + func ) {
2018-01-07 14:20:19 +01:00
if ( ! func - > isConstructor ( ) | | func - > minArgCount ( ) ! = 1 )
continue ;
const Variable * firstArg = func - > getArgumentVar ( 0 ) ;
2020-09-21 19:30:47 +02:00
if ( firstArg - > type ( ) = = scope . definedType ) {
2018-01-07 14:20:19 +01:00
if ( firstArg - > isRValueReference ( ) )
func - > type = Function : : eMoveConstructor ;
2018-01-20 14:46:09 +01:00
else if ( firstArg - > isReference ( ) & & ! firstArg - > isPointer ( ) )
2018-01-07 14:20:19 +01:00
func - > type = Function : : eCopyConstructor ;
}
if ( func - > type = = Function : : eCopyConstructor | |
func - > type = = Function : : eMoveConstructor )
2020-09-21 19:30:47 +02:00
scope . numCopyOrMoveConstructors + + ;
2018-01-07 14:20:19 +01:00
}
}
}
2017-01-01 11:34:05 +01:00
void SymbolDatabase : : createSymbolDatabaseFunctionScopes ( )
{
2012-10-10 20:42:07 +02:00
// fill in function scopes
2022-10-02 07:12:40 +02:00
for ( const Scope & scope : scopeList ) {
2020-09-21 19:30:47 +02:00
if ( scope . type = = Scope : : eFunction )
functionScopes . push_back ( & scope ) ;
2012-10-10 20:42:07 +02:00
}
2017-01-01 11:34:05 +01:00
}
2012-10-10 20:42:07 +02:00
2017-01-01 11:34:05 +01:00
void SymbolDatabase : : createSymbolDatabaseClassAndStructScopes ( )
{
2012-10-10 20:42:07 +02:00
// fill in class and struct scopes
2022-10-02 07:12:40 +02:00
for ( const Scope & scope : scopeList ) {
2020-09-21 19:30:47 +02:00
if ( scope . isClassOrStruct ( ) )
classAndStructScopes . push_back ( & scope ) ;
2012-10-08 16:15:07 +02:00
}
2017-01-01 11:34:05 +01:00
}
2012-10-08 16:15:07 +02:00
2017-01-01 11:34:05 +01:00
void SymbolDatabase : : createSymbolDatabaseFunctionReturnTypes ( )
{
2013-08-26 06:03:26 +02:00
// fill in function return types
2020-09-21 19:30:47 +02:00
for ( Scope & scope : scopeList ) {
2013-08-26 06:03:26 +02:00
std : : list < Function > : : iterator func ;
2020-09-21 19:30:47 +02:00
for ( func = scope . functionList . begin ( ) ; func ! = scope . functionList . end ( ) ; + + func ) {
2013-08-26 06:03:26 +02:00
// add return types
if ( func - > retDef ) {
const Token * type = func - > retDef ;
2016-04-22 06:02:54 +02:00
while ( Token : : Match ( type , " static|const|struct|union|enum " ) )
2013-08-26 06:03:26 +02:00
type = type - > next ( ) ;
2016-06-05 14:08:33 +02:00
if ( type ) {
2020-09-21 19:30:47 +02:00
func - > retType = findVariableTypeInBase ( & scope , type ) ;
2016-06-05 14:08:33 +02:00
if ( ! func - > retType )
func - > retType = findTypeInNested ( type , func - > nestedIn ) ;
}
2013-08-26 06:03:26 +02:00
}
}
}
2017-01-01 11:34:05 +01:00
}
2013-08-26 06:03:26 +02:00
2017-01-01 11:34:05 +01:00
void SymbolDatabase : : createSymbolDatabaseNeedInitialization ( )
{
2018-06-16 16:10:28 +02:00
if ( mTokenizer - > isC ( ) ) {
2015-01-21 10:34:58 +01:00
// For C code it is easy, as there are no constructors and no default values
2022-05-29 17:06:33 +02:00
for ( const Scope & scope : scopeList ) {
2020-09-21 19:30:47 +02:00
if ( scope . definedType )
scope . definedType - > needInitialization = Type : : NeedInitialization : : True ;
2015-01-21 10:34:58 +01:00
}
} else {
// For C++, it is more difficult: Determine if user defined type needs initialization...
unsigned int unknowns = 0 ; // stop checking when there are no unknowns
unsigned int retry = 0 ; // bail if we don't resolve all the variable types for some reason
2010-12-02 07:35:01 +01:00
2015-01-21 10:34:58 +01:00
do {
unknowns = 0 ;
2013-07-08 11:45:26 +02:00
2020-09-21 19:30:47 +02:00
for ( Scope & scope : scopeList ) {
2021-01-06 08:53:13 +01:00
if ( ! scope . isClassOrStructOrUnion ( ) )
continue ;
2020-09-21 19:30:47 +02:00
if ( ! scope . definedType ) {
2019-09-25 15:25:19 +02:00
mBlankTypes . emplace_back ( ) ;
2020-09-21 19:30:47 +02:00
scope . definedType = & mBlankTypes . back ( ) ;
2015-01-21 10:34:58 +01:00
}
2010-12-02 07:35:01 +01:00
2020-09-21 19:30:47 +02:00
if ( scope . isClassOrStruct ( ) & & scope . definedType - > needInitialization = = Type : : NeedInitialization : : Unknown ) {
2015-01-21 10:34:58 +01:00
// check for default constructor
bool hasDefaultConstructor = false ;
2011-01-15 07:59:37 +01:00
2022-05-29 17:06:33 +02:00
for ( const Function & func : scope . functionList ) {
2021-08-09 12:43:21 +02:00
if ( func . type = = Function : : eConstructor ) {
2015-01-21 10:34:58 +01:00
// check for no arguments: func ( )
2021-08-09 12:43:21 +02:00
if ( func . argCount ( ) = = 0 ) {
2015-01-21 10:34:58 +01:00
hasDefaultConstructor = true ;
break ;
2010-12-02 07:35:01 +01:00
}
2015-01-21 10:34:58 +01:00
/** check for arguments with default values */
2021-08-09 12:43:21 +02:00
else if ( func . argCount ( ) = = func . initializedArgCount ( ) ) {
2015-01-21 10:34:58 +01:00
hasDefaultConstructor = true ;
break ;
}
}
2010-12-02 07:35:01 +01:00
}
2015-01-21 10:34:58 +01:00
// User defined types with user defined default constructor doesn't need initialization.
// We assume the default constructor initializes everything.
// Another check will figure out if the constructor actually initializes everything.
if ( hasDefaultConstructor )
2020-09-21 19:30:47 +02:00
scope . definedType - > needInitialization = Type : : NeedInitialization : : False ;
2015-01-21 10:34:58 +01:00
// check each member variable to see if it needs initialization
else {
bool needInitialization = false ;
bool unknown = false ;
2021-08-09 12:43:21 +02:00
for ( const Variable & var : scope . varlist ) {
if ( var . isClass ( ) ) {
if ( var . type ( ) ) {
2015-01-21 10:34:58 +01:00
// does this type need initialization?
2022-01-06 15:21:05 +01:00
if ( var . type ( ) - > needInitialization = = Type : : NeedInitialization : : True & & ! var . hasDefault ( ) )
2015-01-21 10:34:58 +01:00
needInitialization = true ;
2021-08-09 12:43:21 +02:00
else if ( var . type ( ) - > needInitialization = = Type : : NeedInitialization : : Unknown ) {
if ( ! ( var . valueType ( ) & & var . valueType ( ) - > type = = ValueType : : CONTAINER ) )
2019-01-31 16:53:51 +01:00
unknown = true ;
}
2015-01-21 10:34:58 +01:00
}
2021-08-09 12:43:21 +02:00
} else if ( ! var . hasDefault ( ) & & ! var . isStatic ( ) ) {
2015-01-21 10:34:58 +01:00
needInitialization = true ;
2021-08-09 12:43:21 +02:00
break ;
}
2015-01-21 10:34:58 +01:00
}
2010-12-02 07:35:01 +01:00
if ( needInitialization )
2020-09-21 19:30:47 +02:00
scope . definedType - > needInitialization = Type : : NeedInitialization : : True ;
2015-01-21 10:34:58 +01:00
else if ( ! unknown )
2020-09-21 19:30:47 +02:00
scope . definedType - > needInitialization = Type : : NeedInitialization : : False ;
2017-09-12 22:20:07 +02:00
else {
2020-09-21 19:30:47 +02:00
if ( scope . definedType - > needInitialization = = Type : : NeedInitialization : : Unknown )
2017-09-12 22:20:07 +02:00
unknowns + + ;
}
2015-01-21 10:34:58 +01:00
}
2020-09-21 19:30:47 +02:00
} else if ( scope . type = = Scope : : eUnion & & scope . definedType - > needInitialization = = Type : : NeedInitialization : : Unknown )
scope . definedType - > needInitialization = Type : : NeedInitialization : : True ;
2015-01-21 10:34:58 +01:00
}
2010-12-02 07:35:01 +01:00
2015-01-21 10:34:58 +01:00
retry + + ;
} while ( unknowns & & retry < 100 ) ;
2010-12-02 07:35:01 +01:00
2015-01-21 10:34:58 +01:00
// this shouldn't happen so output a debug warning
2018-06-16 16:10:28 +02:00
if ( retry = = 100 & & mSettings - > debugwarnings ) {
2020-09-21 19:30:47 +02:00
for ( const Scope & scope : scopeList ) {
if ( scope . isClassOrStruct ( ) & & scope . definedType - > needInitialization = = Type : : NeedInitialization : : Unknown )
2020-12-31 19:24:16 +01:00
debugMessage ( scope . classDef , " debug " , " SymbolDatabase couldn't resolve all user defined types. " ) ;
2015-01-21 10:34:58 +01:00
}
2010-12-02 07:35:01 +01:00
}
2010-11-13 08:08:45 +01:00
}
2017-01-01 11:34:05 +01:00
}
2011-02-26 21:57:16 +01:00
2017-01-01 11:34:05 +01:00
void SymbolDatabase : : createSymbolDatabaseVariableSymbolTable ( )
{
2011-02-26 21:57:16 +01:00
// create variable symbol table
2018-06-16 20:31:47 +02:00
mVariableList . resize ( mTokenizer - > varIdCount ( ) + 1 ) ;
std : : fill_n ( mVariableList . begin ( ) , mVariableList . size ( ) , ( const Variable * ) nullptr ) ;
2011-02-26 21:57:16 +01:00
// check all scopes for variables
2020-09-21 19:30:47 +02:00
for ( Scope & scope : scopeList ) {
2011-02-26 21:57:16 +01:00
// add all variables
2021-08-09 12:43:21 +02:00
for ( Variable & var : scope . varlist ) {
const unsigned int varId = var . declarationId ( ) ;
2011-02-26 21:57:16 +01:00
if ( varId )
2021-08-09 12:43:21 +02:00
mVariableList [ varId ] = & var ;
2013-08-12 06:21:03 +02:00
// fix up variables without type
2021-08-09 12:43:21 +02:00
if ( ! var . type ( ) & & ! var . typeStartToken ( ) - > isStandardType ( ) ) {
const Type * type = findType ( var . typeStartToken ( ) , & scope ) ;
2013-08-12 06:21:03 +02:00
if ( type )
2021-08-09 12:43:21 +02:00
var . type ( type ) ;
2013-08-12 06:21:03 +02:00
}
2011-02-26 21:57:16 +01:00
}
2013-01-16 15:37:07 +01:00
// add all function parameters
2020-09-21 19:30:47 +02:00
for ( Function & func : scope . functionList ) {
2021-08-09 12:43:21 +02:00
for ( Variable & arg : func . argumentList ) {
2011-02-26 21:57:16 +01:00
// check for named parameters
2021-08-09 12:43:21 +02:00
if ( arg . nameToken ( ) & & arg . declarationId ( ) ) {
const unsigned int declarationId = arg . declarationId ( ) ;
2021-08-09 13:17:48 +02:00
mVariableList [ declarationId ] = & arg ;
2013-08-12 06:21:03 +02:00
// fix up parameters without type
2021-08-09 12:43:21 +02:00
if ( ! arg . type ( ) & & ! arg . typeStartToken ( ) - > isStandardType ( ) ) {
const Type * type = findTypeInNested ( arg . typeStartToken ( ) , & scope ) ;
2013-08-12 06:21:03 +02:00
if ( type )
2021-08-09 12:43:21 +02:00
arg . type ( type ) ;
2013-08-12 06:21:03 +02:00
}
2011-02-26 21:57:16 +01:00
}
}
}
}
2011-06-24 04:35:15 +02:00
2013-01-25 06:49:04 +01:00
// fill in missing variables if possible
2022-10-11 20:47:07 +02:00
for ( const Scope * func : functionScopes ) {
2018-04-27 22:36:30 +02:00
for ( const Token * tok = func - > bodyStart - > next ( ) ; tok & & tok ! = func - > bodyEnd ; tok = tok - > next ( ) ) {
2013-02-20 07:46:06 +01:00
// check for member variable
2022-10-11 20:47:07 +02:00
if ( ! Token : : Match ( tok , " %var% .|[ " ) )
continue ;
const Token * tokDot = tok - > next ( ) ;
while ( Token : : simpleMatch ( tokDot , " [ " ) )
tokDot = tokDot - > link ( ) - > next ( ) ;
if ( ! Token : : Match ( tokDot , " . %var% " ) )
continue ;
const Token * member = tokDot - > next ( ) ;
if ( mVariableList [ member - > varId ( ) ] = = nullptr ) {
const Variable * var1 = mVariableList [ tok - > varId ( ) ] ;
if ( var1 & & var1 - > typeScope ( ) ) {
const Variable * memberVar = var1 - > typeScope ( ) - > getVariable ( member - > str ( ) ) ;
if ( memberVar ) {
// add this variable to the look up table
mVariableList [ member - > varId ( ) ] = memberVar ;
2013-01-25 06:49:04 +01:00
}
}
}
}
}
2017-01-01 11:34:05 +01:00
}
2013-01-25 06:49:04 +01:00
2017-01-01 11:34:05 +01:00
void SymbolDatabase : : createSymbolDatabaseSetScopePointers ( )
{
2021-10-20 20:41:42 +02:00
auto setScopePointers = [ ] ( const Scope & scope , const Token * bodyStart , const Token * bodyEnd ) {
2021-08-10 07:00:11 +02:00
assert ( bodyStart ) ;
assert ( bodyEnd ) ;
2017-09-20 23:06:19 +02:00
2021-08-10 07:00:11 +02:00
const_cast < Token * > ( bodyEnd ) - > scope ( & scope ) ;
2017-09-20 23:06:19 +02:00
2021-08-10 07:00:11 +02:00
for ( Token * tok = const_cast < Token * > ( bodyStart ) ; tok ! = bodyEnd ; tok = tok - > next ( ) ) {
if ( bodyStart ! = bodyEnd & & tok - > str ( ) = = " { " ) {
2017-09-20 23:06:19 +02:00
bool isEndOfScope = false ;
2021-08-10 07:00:11 +02:00
for ( Scope * innerScope : scope . nestedList ) {
const auto & list = innerScope - > bodyStartList ;
if ( std : : find ( list . begin ( ) , list . end ( ) , tok ) ! = list . end ( ) ) { // Is begin of inner scope
2017-09-20 23:06:19 +02:00
tok = tok - > link ( ) ;
2021-08-10 07:00:11 +02:00
if ( tok - > next ( ) = = bodyEnd | | ! tok - > next ( ) ) {
2017-09-20 23:06:19 +02:00
isEndOfScope = true ;
2014-11-01 14:36:17 +01:00
break ;
}
2017-09-20 23:06:19 +02:00
tok = tok - > next ( ) ;
2014-11-01 14:36:17 +01:00
break ;
2017-09-20 23:06:19 +02:00
}
2014-11-01 14:36:17 +01:00
}
2017-09-20 23:06:19 +02:00
if ( isEndOfScope )
break ;
2014-11-01 14:36:17 +01:00
}
2021-08-09 12:43:21 +02:00
tok - > scope ( & scope ) ;
2014-11-01 14:36:17 +01:00
}
2021-08-10 07:00:11 +02:00
} ;
// Set scope pointers
2022-10-02 07:12:40 +02:00
for ( const Scope & scope : scopeList ) {
2021-08-10 07:00:11 +02:00
if ( scope . type = = Scope : : eGlobal )
setScopePointers ( scope , mTokenizer - > list . front ( ) , mTokenizer - > list . back ( ) ) ;
else {
for ( const Token * bodyStart : scope . bodyStartList )
setScopePointers ( scope , bodyStart , bodyStart - > link ( ) ) ;
}
2014-11-01 14:36:17 +01:00
}
2017-01-01 11:34:05 +01:00
}
2014-11-01 14:36:17 +01:00
2017-03-24 12:19:14 +01:00
void SymbolDatabase : : createSymbolDatabaseSetFunctionPointers ( bool firstPass )
2017-01-01 11:34:05 +01:00
{
2017-03-24 12:19:14 +01:00
if ( firstPass ) {
// Set function definition and declaration pointers
2021-08-09 12:43:21 +02:00
for ( const Scope & scope : scopeList ) {
for ( const Function & func : scope . functionList ) {
if ( func . tokenDef )
const_cast < Token * > ( func . tokenDef ) - > function ( & func ) ;
2014-11-01 14:36:17 +01:00
2021-08-09 12:43:21 +02:00
if ( func . token )
const_cast < Token * > ( func . token ) - > function ( & func ) ;
2017-03-24 12:19:14 +01:00
}
2014-11-01 14:36:17 +01:00
}
}
// Set function call pointers
2018-06-16 16:10:28 +02:00
for ( const Token * tok = mTokenizer - > list . front ( ) ; tok ! = mTokenizer - > list . back ( ) ; tok = tok - > next ( ) ) {
2022-03-14 19:15:48 +01:00
if ( tok - > isName ( ) & & ! tok - > function ( ) & & tok - > varId ( ) = = 0 & & Token : : Match ( tok , " %name% [(,)>;] " ) & & ! isReservedName ( tok - > str ( ) ) ) {
2020-09-23 22:10:47 +02:00
if ( tok - > next ( ) - > str ( ) = = " > " & & ! tok - > next ( ) - > link ( ) )
continue ;
if ( tok - > next ( ) - > str ( ) ! = " ( " ) {
const Token * start = tok ;
while ( Token : : Match ( start - > tokAt ( - 2 ) , " %name% :: " ) )
start = start - > tokAt ( - 2 ) ;
2022-03-14 19:15:48 +01:00
if ( ! Token : : Match ( start - > previous ( ) , " [(,<=] " ) & & ! Token : : Match ( start - > tokAt ( - 2 ) , " [(,<=] & " ) & & ! Token : : Match ( start , " %name% ; " ) )
2020-09-23 22:10:47 +02:00
continue ;
}
2017-03-24 12:19:14 +01:00
const Function * function = findFunction ( tok ) ;
2020-09-23 22:10:47 +02:00
if ( ! function )
continue ;
const_cast < Token * > ( tok ) - > function ( function ) ;
if ( tok - > next ( ) - > str ( ) ! = " ( " )
const_cast < Function * > ( function ) - > functionPointerUsage = tok ;
2014-11-01 14:36:17 +01:00
}
}
2014-11-13 06:29:51 +01:00
// Set C++ 11 delegate constructor function call pointers
2021-08-09 12:43:21 +02:00
for ( const Scope & scope : scopeList ) {
for ( const Function & func : scope . functionList ) {
2014-11-13 06:29:51 +01:00
// look for initializer list
2021-08-09 12:43:21 +02:00
if ( func . isConstructor ( ) & & func . functionScope & & func . functionScope - > functionOf & & func . arg ) {
const Token * tok = func . arg - > link ( ) - > next ( ) ;
2017-09-02 22:54:23 +02:00
if ( tok - > str ( ) = = " noexcept " ) {
2017-09-06 17:00:23 +02:00
const Token * closingParenTok = tok - > linkAt ( 1 ) ;
if ( ! closingParenTok | | ! closingParenTok - > next ( ) ) {
2017-09-02 22:54:23 +02:00
continue ;
}
2017-09-06 17:00:23 +02:00
tok = closingParenTok - > next ( ) ;
2017-09-02 22:54:23 +02:00
}
if ( tok - > str ( ) ! = " : " ) {
continue ;
}
tok = tok - > next ( ) ;
2021-08-09 12:43:21 +02:00
while ( tok & & tok ! = func . functionScope - > bodyStart ) {
2015-05-10 11:27:47 +02:00
if ( Token : : Match ( tok , " %name% {|( " ) ) {
2021-08-09 12:43:21 +02:00
if ( tok - > str ( ) = = func . tokenDef - > str ( ) ) {
const Function * function = func . functionScope - > functionOf - > findFunction ( tok ) ;
2016-04-22 06:02:54 +02:00
if ( function )
const_cast < Token * > ( tok ) - > function ( function ) ;
2014-11-13 06:29:51 +01:00
break ;
}
tok = tok - > linkAt ( 1 ) ;
}
tok = tok - > next ( ) ;
}
}
}
}
2017-01-01 11:34:05 +01:00
}
2014-11-13 06:29:51 +01:00
2017-01-01 11:34:05 +01:00
void SymbolDatabase : : createSymbolDatabaseSetTypePointers ( )
{
2022-10-06 20:12:07 +02:00
std : : unordered_set < std : : string > typenames ;
2018-05-09 13:48:55 +02:00
for ( const Type & t : typeList ) {
typenames . insert ( t . name ( ) ) ;
}
2015-08-14 20:46:13 +02:00
// Set type pointers
2018-06-16 16:10:28 +02:00
for ( const Token * tok = mTokenizer - > list . front ( ) ; tok ! = mTokenizer - > list . back ( ) ; tok = tok - > next ( ) ) {
2016-04-22 06:02:54 +02:00
if ( ! tok - > isName ( ) | | tok - > varId ( ) | | tok - > function ( ) | | tok - > type ( ) | | tok - > enumerator ( ) )
2015-08-14 20:46:13 +02:00
continue ;
2018-05-09 13:48:55 +02:00
if ( typenames . find ( tok - > str ( ) ) = = typenames . end ( ) )
continue ;
2016-04-22 06:02:54 +02:00
const Type * type = findVariableType ( tok - > scope ( ) , tok ) ;
if ( type )
2022-03-02 07:46:47 +01:00
const_cast < Token * > ( tok ) - > type ( type ) ; // TODO: avoid const_cast
2015-08-14 20:46:13 +02:00
}
2017-01-01 11:34:05 +01:00
}
2015-08-14 20:46:13 +02:00
2020-02-14 09:40:27 +01:00
void SymbolDatabase : : createSymbolDatabaseSetSmartPointerType ( )
{
for ( Scope & scope : scopeList ) {
for ( Variable & var : scope . varlist ) {
if ( var . valueType ( ) & & var . valueType ( ) - > smartPointerTypeToken & & ! var . valueType ( ) - > smartPointerType ) {
ValueType vt ( * var . valueType ( ) ) ;
vt . smartPointerType = vt . smartPointerTypeToken - > type ( ) ;
var . setValueType ( vt ) ;
}
}
}
}
2017-03-30 10:07:58 +02:00
void SymbolDatabase : : fixVarId ( VarIdMap & varIds , const Token * vartok , Token * membertok , const Variable * membervar )
{
VarIdMap : : iterator varId = varIds . find ( vartok - > varId ( ) ) ;
if ( varId = = varIds . end ( ) ) {
MemberIdMap memberId ;
if ( membertok - > varId ( ) = = 0 ) {
2018-06-16 16:10:28 +02:00
memberId [ membervar - > nameToken ( ) - > varId ( ) ] = const_cast < Tokenizer * > ( mTokenizer ) - > newVarId ( ) ;
2018-06-16 20:31:47 +02:00
mVariableList . push_back ( membervar ) ;
2017-03-30 10:07:58 +02:00
} else
2018-06-16 20:31:47 +02:00
mVariableList [ membertok - > varId ( ) ] = membervar ;
2017-03-30 10:07:58 +02:00
varIds . insert ( std : : make_pair ( vartok - > varId ( ) , memberId ) ) ;
varId = varIds . find ( vartok - > varId ( ) ) ;
}
MemberIdMap : : iterator memberId = varId - > second . find ( membervar - > nameToken ( ) - > varId ( ) ) ;
if ( memberId = = varId - > second . end ( ) ) {
if ( membertok - > varId ( ) = = 0 ) {
2018-06-16 16:10:28 +02:00
varId - > second . insert ( std : : make_pair ( membervar - > nameToken ( ) - > varId ( ) , const_cast < Tokenizer * > ( mTokenizer ) - > newVarId ( ) ) ) ;
2018-06-16 20:31:47 +02:00
mVariableList . push_back ( membervar ) ;
2017-09-06 17:02:27 +02:00
memberId = varId - > second . find ( membervar - > nameToken ( ) - > varId ( ) ) ;
2017-03-30 10:07:58 +02:00
} else
2018-06-16 20:31:47 +02:00
mVariableList [ membertok - > varId ( ) ] = membervar ;
2017-03-30 10:07:58 +02:00
}
if ( membertok - > varId ( ) = = 0 )
membertok - > varId ( memberId - > second ) ;
}
2017-01-01 11:34:05 +01:00
void SymbolDatabase : : createSymbolDatabaseSetVariablePointers ( )
{
2017-03-30 10:07:58 +02:00
VarIdMap varIds ;
2022-07-19 20:42:54 +02:00
auto setMemberVar = [ & ] ( const Variable * membervar , Token * membertok , const Token * vartok ) - > void {
if ( membervar ) {
membertok - > variable ( membervar ) ;
if ( vartok & & ( membertok - > varId ( ) = = 0 | | mVariableList [ membertok - > varId ( ) ] = = nullptr ) )
fixVarId ( varIds , vartok , membertok , membervar ) ;
}
} ;
2014-11-01 14:36:17 +01:00
// Set variable pointers
2018-06-16 16:10:28 +02:00
for ( const Token * tok = mTokenizer - > list . front ( ) ; tok ! = mTokenizer - > list . back ( ) ; tok = tok - > next ( ) ) {
2014-11-01 14:36:17 +01:00
if ( tok - > varId ( ) )
2022-07-19 20:42:54 +02:00
const_cast < Token * > ( tok ) - > variable ( getVariableFromVarId ( tok - > varId ( ) ) ) ;
2014-11-01 14:36:17 +01:00
// Set Token::variable pointer for array member variable
// Since it doesn't point at a fixed location it doesn't have varid
2022-07-19 20:42:54 +02:00
const bool isVar = tok - > variable ( ) & & ( tok - > variable ( ) - > typeScope ( ) | | tok - > variable ( ) - > isSmartPointer ( ) | |
( tok - > valueType ( ) & & ( tok - > valueType ( ) - > type = = ValueType : : CONTAINER | | tok - > valueType ( ) - > type = = ValueType : : ITERATOR ) ) ) ;
2022-03-09 18:22:30 +01:00
const bool isArrayAccess = isVar & & Token : : simpleMatch ( tok - > astParent ( ) , " [ " ) ;
const bool isDirectAccess = isVar & & ! isArrayAccess & & Token : : simpleMatch ( tok - > astParent ( ) , " . " ) ;
const bool isDerefAccess = isVar & & ! isDirectAccess & & Token : : simpleMatch ( tok - > astParent ( ) , " * " ) & & Token : : simpleMatch ( tok - > astParent ( ) - > astParent ( ) , " . " ) ;
if ( isVar & & ( isArrayAccess | | isDirectAccess | | isDerefAccess ) ) {
Token * membertok { } ;
if ( isArrayAccess ) {
membertok = const_cast < Token * > ( tok - > astParent ( ) ) ;
while ( Token : : simpleMatch ( membertok , " [ " ) )
membertok = membertok - > astParent ( ) ;
if ( membertok )
membertok = membertok - > astOperand2 ( ) ;
}
else if ( isDirectAccess ) {
membertok = const_cast < Token * > ( tok - > astParent ( ) - > astOperand2 ( ) ) ;
if ( membertok = = tok ) {
Token * gptok = const_cast < Token * > ( tok - > astParent ( ) - > astParent ( ) ) ;
if ( Token : : simpleMatch ( gptok , " . " ) ) // chained access
membertok = gptok - > astOperand2 ( ) ;
else if ( Token : : simpleMatch ( gptok , " [ " ) & & Token : : simpleMatch ( gptok - > astParent ( ) , " . " ) )
membertok = gptok - > astParent ( ) - > astOperand2 ( ) ;
}
}
else { // isDerefAccess
membertok = const_cast < Token * > ( tok - > astParent ( ) ) ;
while ( Token : : simpleMatch ( membertok , " * " ) )
membertok = membertok - > astParent ( ) ;
if ( membertok )
membertok = membertok - > astOperand2 ( ) ;
}
2014-11-01 14:36:17 +01:00
2022-04-08 08:23:10 +02:00
if ( membertok & & membertok ! = tok ) {
2014-11-01 14:36:17 +01:00
const Variable * var = tok - > variable ( ) ;
2020-02-16 16:02:22 +01:00
if ( var - > typeScope ( ) ) {
2014-11-01 14:36:17 +01:00
const Variable * membervar = var - > typeScope ( ) - > getVariable ( membertok - > str ( ) ) ;
2022-07-19 20:42:54 +02:00
setMemberVar ( membervar , membertok , tok ) ;
2020-02-16 16:02:22 +01:00
} else if ( const : : Type * type = var - > smartPointerType ( ) ) {
2019-10-20 17:00:15 +02:00
const Scope * classScope = type - > classScope ;
const Variable * membervar = classScope ? classScope - > getVariable ( membertok - > str ( ) ) : nullptr ;
2022-07-19 20:42:54 +02:00
setMemberVar ( membervar , membertok , tok ) ;
2020-02-16 16:02:22 +01:00
} else if ( tok - > valueType ( ) & & tok - > valueType ( ) - > type = = ValueType : : CONTAINER ) {
2022-03-09 20:25:58 +01:00
if ( Token : : Match ( var - > typeStartToken ( ) , " std :: %type% < %name% " ) ) {
const Token * type2tok = var - > typeStartToken ( ) - > tokAt ( 4 ) ;
while ( type2tok & & type2tok - > isKeyword ( ) )
type2tok = type2tok - > next ( ) ;
const Type * type2 = type2tok ? type2tok - > type ( ) : nullptr ;
2020-05-10 22:16:58 +02:00
if ( type2 & & type2 - > classScope & & type2 - > classScope - > definedType ) {
const Variable * membervar = type2 - > classScope - > getVariable ( membertok - > str ( ) ) ;
2022-07-19 20:42:54 +02:00
setMemberVar ( membervar , membertok , tok ) ;
2017-03-24 01:14:49 +01:00
}
}
2022-07-19 20:42:54 +02:00
} else if ( const Type * iterType = var - > iteratorType ( ) ) {
if ( iterType - > classScope & & iterType - > classScope - > definedType ) {
const Variable * membervar = iterType - > classScope - > getVariable ( membertok - > str ( ) ) ;
setMemberVar ( membervar , membertok , tok ) ;
}
2014-11-01 14:36:17 +01:00
}
}
}
// check for function returning record type
// func(...).var
// func(...)[...].var
else if ( tok - > function ( ) & & tok - > next ( ) - > str ( ) = = " ( " & &
2015-01-31 10:50:39 +01:00
( Token : : Match ( tok - > next ( ) - > link ( ) , " ) . %name% !!( " ) | |
( Token : : Match ( tok - > next ( ) - > link ( ) , " ) [ " ) & & Token : : Match ( tok - > next ( ) - > link ( ) - > next ( ) - > link ( ) , " ] . %name% !!( " ) ) ) ) {
2014-11-01 14:36:17 +01:00
const Type * type = tok - > function ( ) - > retType ;
if ( type ) {
Token * membertok ;
if ( tok - > next ( ) - > link ( ) - > next ( ) - > str ( ) = = " . " )
membertok = tok - > next ( ) - > link ( ) - > next ( ) - > next ( ) ;
else
membertok = tok - > next ( ) - > link ( ) - > next ( ) - > link ( ) - > next ( ) - > next ( ) ;
const Variable * membervar = membertok - > variable ( ) ;
if ( ! membervar ) {
if ( type - > classScope ) {
membervar = type - > classScope - > getVariable ( membertok - > str ( ) ) ;
2022-07-19 20:42:54 +02:00
setMemberVar ( membervar , membertok , tok - > function ( ) - > retDef ) ;
2014-11-01 14:36:17 +01:00
}
}
}
}
}
2017-01-01 11:34:05 +01:00
}
2016-04-22 06:02:54 +02:00
2017-01-01 11:34:05 +01:00
void SymbolDatabase : : createSymbolDatabaseEnums ( )
{
2016-05-29 14:45:45 +02:00
// fill in enumerators in enum
2022-10-02 07:12:40 +02:00
for ( const Scope & scope : scopeList ) {
2022-05-08 20:42:06 +02:00
if ( scope . type ! = Scope : : eEnum )
2016-05-29 14:45:45 +02:00
continue ;
// add enumerators to enumerator tokens
2022-10-02 07:12:40 +02:00
for ( const Enumerator & i : scope . enumeratorList )
2019-09-19 20:29:33 +02:00
const_cast < Token * > ( i . name ) - > enumerator ( & i ) ;
2016-05-29 14:45:45 +02:00
}
2022-06-08 16:58:57 +02:00
std : : set < std : : string > tokensThatAreNotEnumeratorValues ;
2022-10-02 07:12:40 +02:00
for ( const Scope & scope : scopeList ) {
2022-05-08 20:42:06 +02:00
if ( scope . type ! = Scope : : eEnum )
2016-05-29 14:45:45 +02:00
continue ;
2022-10-02 07:12:40 +02:00
for ( const Enumerator & enumerator : scope . enumeratorList ) {
2016-05-29 14:45:45 +02:00
// look for initialization tokens that can be converted to enumerators and convert them
if ( enumerator . start ) {
2017-05-25 09:50:14 +02:00
if ( ! enumerator . end )
2018-06-16 16:10:28 +02:00
mTokenizer - > syntaxError ( enumerator . start ) ;
2016-05-29 14:45:45 +02:00
for ( const Token * tok3 = enumerator . start ; tok3 & & tok3 ! = enumerator . end - > next ( ) ; tok3 = tok3 - > next ( ) ) {
if ( tok3 - > tokType ( ) = = Token : : eName ) {
2022-06-08 16:58:57 +02:00
const Enumerator * e = findEnumerator ( tok3 , tokensThatAreNotEnumeratorValues ) ;
2016-05-29 14:45:45 +02:00
if ( e )
const_cast < Token * > ( tok3 ) - > enumerator ( e ) ;
}
}
}
}
}
2016-04-22 06:02:54 +02:00
// find enumerators
2018-06-16 16:10:28 +02:00
for ( const Token * tok = mTokenizer - > list . front ( ) ; tok ! = mTokenizer - > list . back ( ) ; tok = tok - > next ( ) ) {
2016-05-25 15:30:49 +02:00
if ( tok - > tokType ( ) ! = Token : : eName )
2016-04-22 06:02:54 +02:00
continue ;
2022-06-08 16:58:57 +02:00
const Enumerator * enumerator = findEnumerator ( tok , tokensThatAreNotEnumeratorValues ) ;
2016-04-22 06:02:54 +02:00
if ( enumerator )
const_cast < Token * > ( tok ) - > enumerator ( enumerator ) ;
}
2017-01-01 11:34:05 +01:00
}
2016-04-22 06:02:54 +02:00
2019-08-05 07:18:06 +02:00
void SymbolDatabase : : createSymbolDatabaseIncompleteVars ( )
{
2021-01-16 13:52:09 +01:00
static const std : : unordered_set < std : : string > cpp20keywords = {
2019-08-05 07:18:06 +02:00
" alignas " ,
" alignof " ,
" axiom " ,
" co_await " ,
" co_return " ,
" co_yield " ,
" concept " ,
" synchronized " ,
" consteval " ,
" reflexpr " ,
" requires " ,
} ;
2021-01-16 13:52:09 +01:00
static const std : : unordered_set < std : : string > cppkeywords = {
2019-08-05 07:18:06 +02:00
" asm " ,
" auto " ,
" catch " ,
" char " ,
" class " ,
" const " ,
" constexpr " ,
" decltype " ,
" default " ,
" do " ,
" enum " ,
" explicit " ,
" export " ,
" extern " ,
" final " ,
" friend " ,
" inline " ,
" mutable " ,
" namespace " ,
" new " ,
" noexcept " ,
2019-12-01 15:09:21 +01:00
" nullptr " ,
2019-08-05 07:18:06 +02:00
" override " ,
" private " ,
" protected " ,
" public " ,
" register " ,
" sizeof " ,
" static " ,
" static_assert " ,
" struct " ,
" template " ,
" this " ,
" thread_local " ,
" throw " ,
" try " ,
" typedef " ,
" typeid " ,
" typename " ,
" union " ,
" using " ,
" virtual " ,
" void " ,
" volatile " ,
2019-12-01 15:09:21 +01:00
" NULL " ,
2019-08-05 07:18:06 +02:00
} ;
for ( const Token * tok = mTokenizer - > list . front ( ) ; tok ! = mTokenizer - > list . back ( ) ; tok = tok - > next ( ) ) {
const Scope * scope = tok - > scope ( ) ;
if ( ! scope )
continue ;
if ( ! scope - > isExecutable ( ) )
continue ;
2022-06-08 16:58:57 +02:00
if ( tok - > varId ( ) ! = 0 )
2019-08-05 07:18:06 +02:00
continue ;
if ( ! tok - > isNameOnly ( ) )
continue ;
if ( tok - > type ( ) )
continue ;
if ( Token : : Match ( tok - > next ( ) , " ::|.|(|:|%var% " ) )
continue ;
if ( Token : : Match ( tok - > next ( ) , " &|&&|* )|%var% " ) )
continue ;
if ( Token : : simpleMatch ( tok - > next ( ) , " ) " ) & & Token : : simpleMatch ( tok - > next ( ) - > link ( ) - > previous ( ) , " catch ( " ) )
continue ;
// Very likely a typelist
2022-04-05 23:19:17 +02:00
if ( Token : : Match ( tok - > tokAt ( - 2 ) , " %type% , " ) | | Token : : Match ( tok - > next ( ) , " , %type% " ) )
2019-08-05 07:18:06 +02:00
continue ;
// Inside template brackets
if ( Token : : Match ( tok - > next ( ) , " <|> " ) & & tok - > next ( ) - > link ( ) )
continue ;
if ( Token : : simpleMatch ( tok - > previous ( ) , " < " ) & & tok - > previous ( ) - > link ( ) )
continue ;
// Skip goto labels
if ( Token : : simpleMatch ( tok - > previous ( ) , " goto " ) )
continue ;
if ( cppkeywords . count ( tok - > str ( ) ) > 0 )
continue ;
if ( mSettings - > standards . cpp > = Standards : : CPP20 & & cpp20keywords . count ( tok - > str ( ) ) > 0 )
continue ;
2022-03-02 07:46:47 +01:00
const_cast < Token * > ( tok ) - > isIncompleteVar ( true ) ; // TODO: avoid const_cast
2019-08-05 07:18:06 +02:00
}
}
2019-08-08 07:46:47 +02:00
void SymbolDatabase : : createSymbolDatabaseEscapeFunctions ( )
{
2022-05-29 17:06:33 +02:00
for ( const Scope & scope : scopeList ) {
2019-08-08 07:46:47 +02:00
if ( scope . type ! = Scope : : eFunction )
continue ;
Function * function = scope . function ;
if ( ! function )
continue ;
2022-02-06 20:13:44 +01:00
if ( Token : : findsimplematch ( scope . bodyStart , " return " , scope . bodyEnd ) )
continue ;
2020-02-13 16:27:06 +01:00
function - > isEscapeFunction ( isReturnScope ( scope . bodyEnd , & mSettings - > library , nullptr , true ) ) ;
2019-08-08 07:46:47 +02:00
}
}
2021-08-14 06:49:12 +02:00
static bool isExpression ( const Token * tok )
{
2022-04-28 10:48:37 +02:00
if ( ! tok )
return false ;
2022-04-03 20:04:18 +02:00
if ( Token : : simpleMatch ( tok , " { " ) & & tok - > scope ( ) & & tok - > scope ( ) - > bodyStart ! = tok & &
( tok - > astOperand1 ( ) | | tok - > astOperand2 ( ) ) )
return true ;
2021-10-06 08:39:58 +02:00
if ( ! Token : : Match ( tok , " (|.|[|::|?|:|++|--|%cop%|%assign% " ) )
2021-08-14 06:49:12 +02:00
return false ;
if ( Token : : Match ( tok , " *|&|&& " ) ) {
const Token * vartok = findAstNode ( tok , [ & ] ( const Token * tok2 ) {
const Variable * var = tok2 - > variable ( ) ;
if ( ! var )
return false ;
return var - > nameToken ( ) = = tok2 ;
} ) ;
if ( vartok )
return false ;
}
return true ;
}
2022-04-28 10:48:37 +02:00
static std : : string getIncompleteNameID ( const Token * tok )
{
std : : string result = tok - > str ( ) + " @ " ;
while ( Token : : Match ( tok - > astParent ( ) , " .|:: " ) )
tok = tok - > astParent ( ) ;
return result + tok - > expressionString ( ) ;
}
2020-08-20 18:21:29 +02:00
void SymbolDatabase : : createSymbolDatabaseExprIds ( )
{
2021-01-27 19:49:13 +01:00
nonneg int base = 0 ;
2020-08-20 18:21:29 +02:00
// Find highest varId
for ( const Variable * var : mVariableList ) {
if ( ! var )
continue ;
base = std : : max < MathLib : : bigint > ( base , var - > declarationId ( ) ) ;
}
2021-01-27 19:49:13 +01:00
nonneg int id = base + 1 ;
2022-04-28 10:48:37 +02:00
// Find incomplete vars that are used in constant context
std : : unordered_map < std : : string , nonneg int > unknownConstantIds ;
const Token * inConstExpr = nullptr ;
for ( const Token * tok = mTokenizer - > list . front ( ) ; tok ! = mTokenizer - > list . back ( ) ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " decltype|sizeof|typeof ( " ) & & tok - > next ( ) - > link ( ) ) {
tok = tok - > next ( ) - > link ( ) - > previous ( ) ;
} else if ( tok = = inConstExpr ) {
inConstExpr = nullptr ;
} else if ( inConstExpr ) {
if ( ! tok - > isIncompleteVar ( ) )
continue ;
if ( ! isExpression ( tok - > astParent ( ) ) )
continue ;
const std : : string & name = getIncompleteNameID ( tok ) ;
if ( unknownConstantIds . count ( name ) > 0 )
continue ;
unknownConstantIds [ name ] = id + + ;
} else if ( tok - > link ( ) & & tok - > str ( ) = = " < " ) {
inConstExpr = tok - > link ( ) ;
} else if ( Token : : Match ( tok , " %var% [ " ) & & tok - > variable ( ) & & tok - > variable ( ) - > nameToken ( ) = = tok ) {
inConstExpr = tok - > next ( ) - > link ( ) ;
}
}
2020-08-20 18:21:29 +02:00
for ( const Scope * scope : functionScopes ) {
2021-10-06 08:39:58 +02:00
nonneg int thisId = 0 ;
2020-08-20 18:21:29 +02:00
std : : unordered_map < std : : string , std : : vector < Token * > > exprs ;
2022-04-28 10:48:37 +02:00
std : : unordered_map < std : : string , nonneg int > unknownIds ;
// Assign IDs to incomplete vars which are part of an expression
// Such variables should be assumed global
for ( Token * tok = const_cast < Token * > ( scope - > bodyStart ) ; tok ! = scope - > bodyEnd ; tok = tok - > next ( ) ) {
if ( ! tok - > isIncompleteVar ( ) )
continue ;
if ( ! isExpression ( tok - > astParent ( ) ) )
continue ;
const std : : string & name = getIncompleteNameID ( tok ) ;
nonneg int sid = 0 ;
if ( unknownConstantIds . count ( name ) > 0 ) {
sid = unknownConstantIds . at ( name ) ;
tok - > isIncompleteConstant ( true ) ;
} else if ( unknownIds . count ( name ) = = 0 ) {
sid = id + + ;
unknownIds [ name ] = sid ;
} else {
sid = unknownIds . at ( name ) ;
}
assert ( sid > 0 ) ;
tok - > exprId ( sid ) ;
}
2020-08-20 18:21:29 +02:00
// Assign IDs
for ( Token * tok = const_cast < Token * > ( scope - > bodyStart ) ; tok ! = scope - > bodyEnd ; tok = tok - > next ( ) ) {
if ( tok - > varId ( ) > 0 ) {
tok - > exprId ( tok - > varId ( ) ) ;
2021-08-14 06:49:12 +02:00
} else if ( isExpression ( tok ) ) {
2020-08-20 18:21:29 +02:00
exprs [ tok - > str ( ) ] . push_back ( tok ) ;
tok - > exprId ( id + + ) ;
2021-01-27 19:49:13 +01:00
if ( id = = std : : numeric_limits < nonneg int > : : max ( ) ) {
throw InternalError ( nullptr , " Ran out of expression ids. " , InternalError : : INTERNAL ) ;
}
2021-10-06 08:39:58 +02:00
} else if ( isCPP ( ) & & Token : : simpleMatch ( tok , " this " ) ) {
if ( thisId = = 0 )
thisId = id + + ;
tok - > exprId ( thisId ) ;
2020-08-20 18:21:29 +02:00
}
}
// Apply CSE
2020-08-23 17:17:33 +02:00
for ( const auto & p : exprs ) {
2020-08-20 18:21:29 +02:00
const std : : vector < Token * > & tokens = p . second ;
2020-08-23 17:17:33 +02:00
for ( Token * tok1 : tokens ) {
for ( Token * tok2 : tokens ) {
2020-08-20 18:21:29 +02:00
if ( tok1 = = tok2 )
continue ;
if ( tok1 - > exprId ( ) = = tok2 - > exprId ( ) )
continue ;
2021-07-16 18:49:07 +02:00
if ( ! isSameExpression ( isCPP ( ) , true , tok1 , tok2 , mSettings - > library , false , false ) )
2020-08-20 18:21:29 +02:00
continue ;
2022-10-02 07:12:40 +02:00
nonneg int const cid = std : : min ( tok1 - > exprId ( ) , tok2 - > exprId ( ) ) ;
2020-08-20 18:21:29 +02:00
tok1 - > exprId ( cid ) ;
tok2 - > exprId ( cid ) ;
}
}
}
}
}
2019-03-15 19:00:42 +01:00
void SymbolDatabase : : setArrayDimensionsUsingValueFlow ( )
2017-01-01 11:34:05 +01:00
{
2016-04-22 06:02:54 +02:00
// set all unknown array dimensions
2019-03-14 19:57:58 +01:00
for ( const Variable * var : mVariableList ) {
2016-04-22 06:02:54 +02:00
// check each array variable
2019-03-14 19:57:58 +01:00
if ( ! var | | ! var - > isArray ( ) )
2019-03-14 19:53:45 +01:00
continue ;
// check each array dimension
2019-03-14 19:57:58 +01:00
for ( const Dimension & const_dimension : var - > dimensions ( ) ) {
Dimension & dimension = const_cast < Dimension & > ( const_dimension ) ;
2019-03-15 19:00:42 +01:00
if ( dimension . num ! = 0 | | ! dimension . tok )
2019-03-14 19:53:45 +01:00
continue ;
2020-02-19 07:36:02 +01:00
if ( Token : : Match ( dimension . tok - > previous ( ) , " [<,] " ) ) {
if ( dimension . known )
continue ;
if ( ! Token : : Match ( dimension . tok - > previous ( ) , " [<,] " ) )
continue ;
// In template arguments, there might not be AST
// Determine size by using the "raw tokens"
TokenList tokenList ( mSettings ) ;
2020-12-08 10:34:23 +01:00
tokenList . addtoken ( " ; " , 0 , 0 , 0 , false ) ;
2020-02-19 07:36:02 +01:00
bool fail = false ;
for ( const Token * tok = dimension . tok ; tok & & ! Token : : Match ( tok , " [,>] " ) ; tok = tok - > next ( ) ) {
if ( ! tok - > isName ( ) )
2020-12-08 10:34:23 +01:00
tokenList . addtoken ( tok - > str ( ) , 0 , 0 , 0 , false ) ;
2020-02-19 07:36:02 +01:00
else if ( tok - > hasKnownIntValue ( ) )
2020-12-08 10:34:23 +01:00
tokenList . addtoken ( std : : to_string ( tok - > getKnownIntValue ( ) ) , 0 , 0 , 0 , false ) ;
2020-02-19 07:36:02 +01:00
else {
fail = true ;
break ;
}
}
if ( fail )
continue ;
2020-12-08 10:34:23 +01:00
tokenList . addtoken ( " ; " , 0 , 0 , 0 , false ) ;
2020-02-19 07:36:02 +01:00
for ( Token * tok = tokenList . front ( ) ; tok ; ) {
if ( TemplateSimplifier : : simplifyNumericCalculations ( tok , false ) )
tok = tokenList . front ( ) ;
else
tok = tok - > next ( ) ;
}
if ( Token : : Match ( tokenList . front ( ) , " ; %num% ; " ) ) {
dimension . known = true ;
dimension . num = MathLib : : toLongNumber ( tokenList . front ( ) - > next ( ) - > str ( ) ) ;
}
continue ;
}
// Normal array [..dimension..]
2019-03-14 19:53:45 +01:00
dimension . known = false ;
2019-03-15 19:00:42 +01:00
// check for a single token dimension
if ( dimension . tok - > hasKnownIntValue ( ) ) {
dimension . known = true ;
dimension . num = dimension . tok - > getKnownIntValue ( ) ;
continue ;
2016-04-22 06:02:54 +02:00
}
2019-03-14 19:53:45 +01:00
2019-03-15 19:00:42 +01:00
else if ( dimension . tok - > valueType ( ) & & dimension . tok - > valueType ( ) - > pointer = = 0 ) {
int bits = 0 ;
switch ( dimension . tok - > valueType ( ) - > type ) {
case ValueType : : Type : : CHAR :
bits = mSettings - > char_bit ;
break ;
case ValueType : : Type : : SHORT :
bits = mSettings - > short_bit ;
break ;
case ValueType : : Type : : INT :
bits = mSettings - > int_bit ;
break ;
case ValueType : : Type : : LONG :
bits = mSettings - > long_bit ;
break ;
case ValueType : : Type : : LONGLONG :
bits = mSettings - > long_long_bit ;
break ;
default :
break ;
2020-04-21 17:27:51 +02:00
}
2019-03-14 19:53:45 +01:00
2019-06-15 13:23:21 +02:00
if ( bits > 0 & & bits < = 62 ) {
2019-03-16 19:41:13 +01:00
if ( dimension . tok - > valueType ( ) - > sign = = ValueType : : Sign : : UNSIGNED )
2019-03-15 19:00:42 +01:00
dimension . num = 1LL < < bits ;
2019-03-16 19:41:13 +01:00
else
dimension . num = 1LL < < ( bits - 1 ) ;
2019-03-14 19:53:45 +01:00
}
}
2016-04-22 06:02:54 +02:00
}
}
2010-11-13 08:08:45 +01:00
}
2014-11-02 10:36:52 +01:00
SymbolDatabase : : ~ SymbolDatabase ( )
{
2015-08-14 20:46:13 +02:00
// Clear scope, type, function and variable pointers
2018-06-16 16:10:28 +02:00
for ( const Token * tok = mTokenizer - > list . front ( ) ; tok ; tok = tok - > next ( ) ) {
2017-08-09 20:00:26 +02:00
const_cast < Token * > ( tok ) - > scope ( nullptr ) ;
const_cast < Token * > ( tok ) - > type ( nullptr ) ;
const_cast < Token * > ( tok ) - > function ( nullptr ) ;
const_cast < Token * > ( tok ) - > variable ( nullptr ) ;
const_cast < Token * > ( tok ) - > enumerator ( nullptr ) ;
const_cast < Token * > ( tok ) - > setValueType ( nullptr ) ;
2014-11-02 10:36:52 +01:00
}
}
2016-07-17 15:47:32 +02:00
bool SymbolDatabase : : isFunction ( const Token * tok , const Scope * outerScope , const Token * * funcStart , const Token * * argStart , const Token * * declEnd ) const
2010-11-13 08:08:45 +01:00
{
2014-09-29 13:05:51 +02:00
if ( tok - > varId ( ) )
return false ;
2015-01-31 10:50:39 +01:00
// function returning function pointer? '... ( ... %name% ( ... ))( ... ) {'
2018-01-24 09:51:22 +01:00
// function returning reference to array '... ( & %name% ( ... ))[ ... ] {'
2018-04-25 18:48:26 +02:00
// TODO: Activate this again
if ( false & & tok - > str ( ) = = " ( " & & tok - > strAt ( 1 ) ! = " * " & &
2018-01-24 09:51:22 +01:00
( tok - > link ( ) - > previous ( ) - > str ( ) = = " ) " | | Token : : simpleMatch ( tok - > link ( ) - > tokAt ( - 2 ) , " ) const " ) ) ) {
2014-04-01 10:13:00 +02:00
const Token * tok2 = tok - > link ( ) - > next ( ) ;
if ( tok2 & & tok2 - > str ( ) = = " ( " & & Token : : Match ( tok2 - > link ( ) - > next ( ) , " {|;|const|= " ) ) {
2018-01-24 09:51:22 +01:00
const Token * argStartTok ;
if ( tok - > link ( ) - > previous ( ) - > str ( ) = = " const " )
argStartTok = tok - > link ( ) - > linkAt ( - 2 ) ;
else
argStartTok = tok - > link ( ) - > linkAt ( - 1 ) ;
2014-11-30 13:00:27 +01:00
* funcStart = argStartTok - > previous ( ) ;
* argStart = argStartTok ;
2016-07-17 15:47:32 +02:00
* declEnd = Token : : findmatch ( tok2 - > link ( ) - > next ( ) , " {|; " ) ;
2014-04-01 10:13:00 +02:00
return true ;
2018-01-24 09:51:22 +01:00
} else if ( tok2 & & tok2 - > str ( ) = = " [ " ) {
while ( tok2 & & tok2 - > str ( ) = = " [ " )
tok2 = tok2 - > link ( ) - > next ( ) ;
if ( Token : : Match ( tok2 , " {|;|const|= " ) ) {
const Token * argStartTok ;
if ( tok - > link ( ) - > previous ( ) - > str ( ) = = " const " )
argStartTok = tok - > link ( ) - > linkAt ( - 2 ) ;
else
argStartTok = tok - > link ( ) - > linkAt ( - 1 ) ;
* funcStart = argStartTok - > previous ( ) ;
* argStart = argStartTok ;
* declEnd = Token : : findmatch ( tok2 , " {|; " ) ;
return true ;
}
2014-04-01 10:13:00 +02:00
}
2010-11-13 08:08:45 +01:00
}
2020-05-17 17:32:31 +02:00
else if ( ! tok - > isName ( ) | | ! tok - > next ( ) | | ! tok - > next ( ) - > link ( ) )
return false ;
2010-11-13 08:08:45 +01:00
// regular function?
2015-05-26 00:28:08 +02:00
else if ( Token : : Match ( tok , " %name% ( " ) & & ! isReservedName ( tok - > str ( ) ) & & tok - > previous ( ) & &
2016-11-18 22:01:15 +01:00
( Token : : Match ( tok - > previous ( ) , " %name%|>|&|*|::|~ " ) | | // Either a return type or scope qualifier in front of tok
2017-10-15 11:49:36 +02:00
outerScope - > isClassOrStructOrUnion ( ) ) ) { // or a ctor/dtor
2015-02-24 06:11:31 +01:00
const Token * tok1 = tok - > previous ( ) ;
2016-07-17 15:47:32 +02:00
const Token * tok2 = tok - > next ( ) - > link ( ) - > next ( ) ;
2015-02-24 06:11:31 +01:00
2018-06-16 16:10:28 +02:00
if ( ! mTokenizer - > isFunctionHead ( tok - > next ( ) , " ;:{ " ) )
2018-04-27 10:24:02 +02:00
return false ;
2015-02-24 06:11:31 +01:00
// skip over destructor "~"
if ( tok1 - > str ( ) = = " ~ " )
tok1 = tok1 - > previous ( ) ;
// skip over qualification
while ( Token : : simpleMatch ( tok1 , " :: " ) ) {
2016-12-06 22:11:40 +01:00
tok1 = tok1 - > previous ( ) ;
2022-06-08 16:58:57 +02:00
if ( tok1 & & tok1 - > isName ( ) )
2016-12-06 22:11:40 +01:00
tok1 = tok1 - > previous ( ) ;
else if ( tok1 & & tok1 - > str ( ) = = " > " & & tok1 - > link ( ) & & Token : : Match ( tok1 - > link ( ) - > previous ( ) , " %name% " ) )
tok1 = tok1 - > link ( ) - > tokAt ( - 2 ) ;
2015-02-24 06:11:31 +01:00
}
2018-05-10 07:40:01 +02:00
// skip over const, noexcept, throw, override, final and volatile specifiers
2018-12-13 06:34:10 +01:00
while ( Token : : Match ( tok2 , " const|noexcept|throw|override|final|volatile|&|&& " ) ) {
2016-07-17 15:47:32 +02:00
tok2 = tok2 - > next ( ) ;
if ( tok2 & & tok2 - > str ( ) = = " ( " )
tok2 = tok2 - > link ( ) - > next ( ) ;
}
2018-12-13 06:34:10 +01:00
// skip over trailing return type
2016-07-17 15:47:32 +02:00
if ( tok2 & & tok2 - > str ( ) = = " . " ) {
for ( tok2 = tok2 - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
2018-12-13 06:34:10 +01:00
if ( Token : : Match ( tok2 , " ;|{|=|override|final " ) )
2016-07-17 15:47:32 +02:00
break ;
if ( tok2 - > link ( ) & & Token : : Match ( tok2 , " <|[|( " ) )
tok2 = tok2 - > link ( ) ;
}
}
2015-04-04 11:33:25 +02:00
// done if constructor or destructor
if ( ! Token : : Match ( tok1 , " {|}|;|public:|protected:|private: " ) & & tok1 ) {
// skip over pointers and references
2018-04-29 15:35:31 +02:00
while ( Token : : Match ( tok1 , " %type%|*|& " ) & & ! endsWith ( tok1 - > str ( ) , ' : ' ) & & ( ! isReservedName ( tok1 - > str ( ) ) | | tok1 - > str ( ) = = " const " ) )
2016-12-06 22:11:40 +01:00
tok1 = tok1 - > previous ( ) ;
2015-02-24 06:11:31 +01:00
2022-01-16 12:33:31 +01:00
// skip over decltype
if ( Token : : simpleMatch ( tok1 , " ) " ) & & tok1 - > link ( ) & &
Token : : simpleMatch ( tok1 - > link ( ) - > previous ( ) , " decltype ( " ) )
tok1 = tok1 - > link ( ) - > tokAt ( - 2 ) ;
2015-04-04 11:33:25 +02:00
// skip over template
if ( tok1 & & tok1 - > str ( ) = = " > " ) {
if ( tok1 - > link ( ) )
tok1 = tok1 - > link ( ) - > previous ( ) ;
else
return false ;
}
2015-02-24 06:11:31 +01:00
2015-04-04 11:33:25 +02:00
// function can't have number or variable as return type
if ( tok1 & & ( tok1 - > isNumber ( ) | | tok1 - > varId ( ) ) )
2015-02-28 16:07:43 +01:00
return false ;
2015-02-24 06:11:31 +01:00
2015-04-04 11:33:25 +02:00
// skip over return type
2022-06-08 16:58:57 +02:00
if ( tok1 & & tok1 - > isName ( ) ) {
2015-04-04 11:33:25 +02:00
if ( tok1 - > str ( ) = = " return " )
return false ;
2022-03-28 22:44:04 +02:00
if ( tok1 - > str ( ) ! = " friend " )
tok1 = tok1 - > previous ( ) ;
2015-04-04 11:33:25 +02:00
}
2015-02-24 06:11:31 +01:00
2015-04-04 11:33:25 +02:00
// skip over qualification
while ( Token : : simpleMatch ( tok1 , " :: " ) ) {
2016-12-06 22:11:40 +01:00
tok1 = tok1 - > previous ( ) ;
2022-06-08 16:58:57 +02:00
if ( tok1 & & tok1 - > isName ( ) )
2016-12-06 22:11:40 +01:00
tok1 = tok1 - > previous ( ) ;
2018-05-01 07:32:19 +02:00
else if ( tok1 & & tok1 - > str ( ) = = " > " & & tok1 - > link ( ) & & Token : : Match ( tok1 - > link ( ) - > previous ( ) , " %name% " ) )
tok1 = tok1 - > link ( ) - > tokAt ( - 2 ) ;
2022-01-16 12:33:31 +01:00
else if ( Token : : simpleMatch ( tok1 , " ) " ) & & tok1 - > link ( ) & &
Token : : simpleMatch ( tok1 - > link ( ) - > previous ( ) , " decltype ( " ) )
tok1 = tok1 - > link ( ) - > tokAt ( - 2 ) ;
2015-04-04 11:33:25 +02:00
}
// skip over modifiers and other stuff
2017-02-20 23:09:35 +01:00
while ( Token : : Match ( tok1 , " const|static|extern|template|virtual|struct|class|enum|%name% " ) ) {
// friend type func(); is not a function
if ( isCPP ( ) & & tok1 - > str ( ) = = " friend " & & tok2 - > str ( ) = = " ; " )
return false ;
2015-04-04 11:33:25 +02:00
tok1 = tok1 - > previous ( ) ;
2017-02-20 23:09:35 +01:00
}
2015-02-24 06:11:31 +01:00
2015-04-04 11:33:25 +02:00
// should be at a sequence point if this is a function
if ( ! Token : : Match ( tok1 , " >|{|}|;|public:|protected:|private: " ) & & tok1 )
return false ;
}
2015-02-24 06:11:31 +01:00
2014-04-10 16:17:10 +02:00
if ( tok2 & &
2016-07-17 15:47:32 +02:00
( Token : : Match ( tok2 , " ;|{|= " ) | |
2015-01-31 10:50:39 +01:00
( tok2 - > isUpperCaseName ( ) & & Token : : Match ( tok2 , " %name% ;|{ " ) ) | |
( tok2 - > isUpperCaseName ( ) & & Token : : Match ( tok2 , " %name% ( " ) & & tok2 - > next ( ) - > link ( ) - > strAt ( 1 ) = = " { " ) | |
Token : : Match ( tok2 , " : ::| %name% (|::|<|{ " ) | |
2016-07-17 15:47:32 +02:00
Token : : Match ( tok2 , " &|&&| ;|{ " ) | |
Token : : Match ( tok2 , " = delete|default ; " ) ) ) {
2014-03-31 20:33:01 +02:00
* funcStart = tok ;
* argStart = tok - > next ( ) ;
2016-07-17 15:47:32 +02:00
* declEnd = Token : : findmatch ( tok2 , " {|; " ) ;
2014-03-31 20:33:01 +02:00
return true ;
}
2010-11-13 08:08:45 +01:00
}
2014-04-13 13:05:30 +02:00
// UNKNOWN_MACRO(a,b) { ... }
else if ( outerScope - > type = = Scope : : eGlobal & &
2015-01-31 10:50:39 +01:00
Token : : Match ( tok , " %name% ( " ) & &
2014-04-13 13:05:30 +02:00
tok - > isUpperCaseName ( ) & &
2014-05-18 20:39:52 +02:00
Token : : simpleMatch ( tok - > linkAt ( 1 ) , " ) { " ) & &
2014-04-13 13:05:30 +02:00
( ! tok - > previous ( ) | | Token : : Match ( tok - > previous ( ) , " [;{}] " ) ) ) {
* funcStart = tok ;
* argStart = tok - > next ( ) ;
2016-07-17 15:47:32 +02:00
* declEnd = tok - > linkAt ( 1 ) - > next ( ) ;
2014-04-13 13:05:30 +02:00
return true ;
}
2013-01-04 10:35:24 +01:00
// template constructor?
2015-01-31 10:50:39 +01:00
else if ( Token : : Match ( tok , " %name% < " ) & & Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " > ( " ) ) {
2014-04-01 10:13:00 +02:00
const Token * tok2 = tok - > next ( ) - > link ( ) - > next ( ) - > link ( ) ;
if ( Token : : Match ( tok2 , " ) const| ;|{|= " ) | |
2015-01-31 10:50:39 +01:00
Token : : Match ( tok2 , " ) : ::| %name% (|::|<|{ " ) | |
2016-12-06 22:11:40 +01:00
Token : : Match ( tok2 , " ) const| noexcept {|;|( " ) ) {
2014-04-01 10:13:00 +02:00
* funcStart = tok ;
* argStart = tok2 - > link ( ) ;
2016-07-17 15:47:32 +02:00
* declEnd = Token : : findmatch ( tok2 - > next ( ) , " {|; " ) ;
2014-04-01 10:13:00 +02:00
return true ;
}
2013-01-04 10:35:24 +01:00
}
2017-01-06 11:53:17 +01:00
// regular C function with missing return or invalid C++ ?
else if ( Token : : Match ( tok , " %name% ( " ) & & ! isReservedName ( tok - > str ( ) ) & &
Token : : simpleMatch ( tok - > linkAt ( 1 ) , " ) { " ) & &
( ! tok - > previous ( ) | | Token : : Match ( tok - > previous ( ) , " ;|} " ) ) ) {
2018-06-16 16:10:28 +02:00
if ( mTokenizer - > isC ( ) ) {
2020-12-31 19:24:16 +01:00
debugMessage ( tok , " debug " , " SymbolDatabase::isFunction found C function ' " + tok - > str ( ) + " ' without a return type. " ) ;
2017-01-06 11:53:17 +01:00
* funcStart = tok ;
* argStart = tok - > next ( ) ;
* declEnd = tok - > linkAt ( 1 ) - > next ( ) ;
return true ;
}
2018-06-16 16:10:28 +02:00
mTokenizer - > syntaxError ( tok ) ;
2017-01-06 11:53:17 +01:00
}
2010-11-13 08:08:45 +01:00
return false ;
}
2016-02-03 17:08:46 +01:00
void SymbolDatabase : : validateExecutableScopes ( ) const
2015-12-05 20:55:26 +01:00
{
2016-02-03 17:08:46 +01:00
const std : : size_t functions = functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * const scope = functionScopes [ i ] ;
const Function * const function = scope - > function ;
if ( scope - > isExecutable ( ) & & ! function ) {
const std : : list < const Token * > callstack ( 1 , scope - > classDef ) ;
const std : : string msg = std : : string ( " Executable scope ' " ) + scope - > classDef - > str ( ) + " ' with unknown function. " ;
2020-05-23 07:16:49 +02:00
const ErrorMessage errmsg ( callstack , & mTokenizer - > list , Severity : : debug ,
" symbolDatabaseWarning " ,
msg ,
2021-02-24 22:00:06 +01:00
Certainty : : normal ) ;
2018-06-16 16:10:28 +02:00
mErrorLogger - > reportErr ( errmsg ) ;
2016-02-03 17:08:46 +01:00
}
}
}
2015-12-06 08:14:04 +01:00
2016-02-03 21:52:02 +01:00
namespace {
const Function * getFunctionForArgumentvariable ( const Variable * const var , const std : : vector < const Scope * > & functionScopes )
{
const std : : size_t functions = functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * const scope = functionScopes [ i ] ;
const Function * const function = scope - > function ;
if ( function ) {
for ( std : : size_t arg = 0 ; arg < function - > argCount ( ) ; + + arg ) {
if ( var = = function - > getArgumentVar ( arg ) )
return function ;
}
}
}
return nullptr ;
}
}
2016-02-03 17:08:46 +01:00
void SymbolDatabase : : validateVariables ( ) const
{
2018-06-16 20:31:47 +02:00
for ( std : : vector < const Variable * > : : const_iterator iter = mVariableList . begin ( ) ; iter ! = mVariableList . end ( ) ; + + iter ) {
2017-08-28 17:15:15 +02:00
const Variable * const var = * iter ;
if ( var ) {
2016-02-03 21:52:02 +01:00
if ( ! var - > scope ( ) ) {
const Function * function = getFunctionForArgumentvariable ( var , functionScopes ) ;
if ( ! var - > isArgument ( ) | | ( function & & function - > hasBody ( ) ) ) {
throw InternalError ( var - > nameToken ( ) , " Analysis failed (variable without scope). If the code is valid then please report this failure. " , InternalError : : INTERNAL ) ;
//std::cout << "!!!Variable found without scope: " << var->nameToken()->str() << std::endl;
}
}
2015-12-05 20:55:26 +01:00
}
}
}
2016-02-03 17:08:46 +01:00
void SymbolDatabase : : validate ( ) const
{
2018-06-16 16:10:28 +02:00
if ( mSettings - > debugwarnings ) {
2016-02-03 17:08:46 +01:00
validateExecutableScopes ( ) ;
}
2022-01-04 15:48:08 +01:00
// TODO
2016-02-03 17:08:46 +01:00
//validateVariables();
}
2021-04-30 16:47:02 +02:00
void SymbolDatabase : : clangSetVariables ( const std : : vector < const Variable * > & variableList )
{
mVariableList = variableList ;
}
2022-06-15 21:25:55 +02:00
void SymbolDatabase : : debugSymbolDatabase ( ) const
{
if ( ! mSettings - > debugnormal & & ! mSettings - > debugwarnings )
return ;
for ( const Token * tok = mTokenizer - > list . front ( ) ; tok ! = mTokenizer - > list . back ( ) ; tok = tok - > next ( ) ) {
if ( tok - > astParent ( ) & & tok - > astParent ( ) - > getTokenDebug ( ) = = tok - > getTokenDebug ( ) )
continue ;
if ( tok - > getTokenDebug ( ) = = TokenDebug : : ValueType ) {
std : : string msg = " Value type is " ;
ErrorPath errorPath ;
if ( tok - > valueType ( ) ) {
msg + = tok - > valueType ( ) - > str ( ) ;
errorPath . insert ( errorPath . end ( ) , tok - > valueType ( ) - > debugPath . begin ( ) , tok - > valueType ( ) - > debugPath . end ( ) ) ;
} else {
msg + = " missing " ;
}
errorPath . emplace_back ( tok , " " ) ;
mErrorLogger - > reportErr (
{ errorPath , & mTokenizer - > list , Severity : : debug , " valueType " , msg , CWE { 0 } , Certainty : : normal } ) ;
}
}
}
2021-04-30 16:47:02 +02:00
Variable : : Variable ( const Token * name_ , const std : : string & clangType , const Token * typeStart ,
const Token * typeEnd , nonneg int index_ , AccessControl access_ ,
const Type * type_ , const Scope * scope_ )
: mNameToken ( name_ ) ,
2021-08-07 20:51:18 +02:00
mTypeStartToken ( typeStart ) ,
mTypeEndToken ( typeEnd ) ,
mIndex ( index_ ) ,
mAccess ( access_ ) ,
mFlags ( 0 ) ,
mType ( type_ ) ,
mScope ( scope_ ) ,
mValueType ( nullptr )
2021-04-30 16:47:02 +02:00
{
if ( ! mTypeStartToken & & mTypeEndToken ) {
mTypeStartToken = mTypeEndToken ;
while ( Token : : Match ( mTypeStartToken - > previous ( ) , " %type%|*|& " ) )
mTypeStartToken = mTypeStartToken - > previous ( ) ;
}
while ( Token : : Match ( mTypeStartToken , " const|struct|static " ) ) {
if ( mTypeStartToken - > str ( ) = = " static " )
setFlag ( fIsStatic , true ) ;
mTypeStartToken = mTypeStartToken - > next ( ) ;
}
if ( Token : : simpleMatch ( mTypeEndToken , " & " ) )
setFlag ( fIsReference , true ) ;
else if ( Token : : simpleMatch ( mTypeEndToken , " && " ) ) {
setFlag ( fIsReference , true ) ;
setFlag ( fIsRValueRef , true ) ;
}
std : : string : : size_type pos = clangType . find ( " [ " ) ;
if ( pos ! = std : : string : : npos ) {
setFlag ( fIsArray , true ) ;
do {
const std : : string : : size_type pos1 = pos + 1 ;
pos = clangType . find ( " ] " , pos1 ) ;
Dimension dim ;
dim . tok = nullptr ;
dim . known = pos > pos1 ;
if ( pos > pos1 )
dim . num = MathLib : : toLongNumber ( clangType . substr ( pos1 , pos - pos1 ) ) ;
else
dim . num = 0 ;
mDimensions . push_back ( dim ) ;
+ + pos ;
} while ( pos < clangType . size ( ) & & clangType [ pos ] = = ' [ ' ) ;
}
// Is there initialization in variable declaration
const Token * initTok = mNameToken ? mNameToken - > next ( ) : nullptr ;
while ( initTok & & initTok - > str ( ) = = " [ " )
initTok = initTok - > link ( ) - > next ( ) ;
if ( Token : : Match ( initTok , " =|{ " ) | | ( initTok & & initTok - > isSplittedVarDeclEq ( ) ) )
setFlag ( fIsInit , true ) ;
}
2021-01-27 20:03:42 +01:00
Variable : : Variable ( const Variable & var , const Scope * scope )
2021-01-28 13:46:00 +01:00
: mValueType ( nullptr )
2021-01-27 20:03:42 +01:00
{
2021-01-28 13:46:00 +01:00
* this = var ;
mScope = scope ;
2021-01-27 20:03:42 +01:00
}
Variable : : Variable ( const Variable & var )
2021-01-28 13:46:00 +01:00
: mValueType ( nullptr )
2021-01-27 20:03:42 +01:00
{
2021-01-28 13:46:00 +01:00
* this = var ;
2021-01-27 20:03:42 +01:00
}
2018-06-20 10:00:15 +02:00
Variable : : ~ Variable ( )
{
delete mValueType ;
}
2021-01-28 13:46:00 +01:00
Variable & Variable : : operator = ( const Variable & var )
{
if ( this = = & var )
return * this ;
mNameToken = var . mNameToken ;
mTypeStartToken = var . mTypeStartToken ;
mTypeEndToken = var . mTypeEndToken ;
mIndex = var . mIndex ;
mAccess = var . mAccess ;
mFlags = var . mFlags ;
mType = var . mType ;
mScope = var . mScope ;
mDimensions = var . mDimensions ;
delete mValueType ;
if ( var . mValueType )
mValueType = new ValueType ( * var . mValueType ) ;
else
mValueType = nullptr ;
return * this ;
}
2022-07-10 11:33:24 +02:00
bool Variable : : isMember ( ) const {
return mScope & & mScope - > isClassOrStructOrUnion ( ) ;
}
2015-08-29 00:09:33 +02:00
bool Variable : : isPointerArray ( ) const
{
2015-08-28 23:06:39 +02:00
return isArray ( ) & & nameToken ( ) & & nameToken ( ) - > previous ( ) & & ( nameToken ( ) - > previous ( ) - > str ( ) = = " * " ) ;
}
2020-01-11 14:00:41 +01:00
bool Variable : : isUnsigned ( ) const
{
return mValueType ? ( mValueType - > sign = = ValueType : : Sign : : UNSIGNED ) : mTypeStartToken - > isUnsigned ( ) ;
}
2014-10-16 09:11:09 +02:00
const Token * Variable : : declEndToken ( ) const
{
Token const * declEnd = typeStartToken ( ) ;
while ( declEnd & & ! Token : : Match ( declEnd , " [;,)={] " ) ) {
2021-09-05 16:35:08 +02:00
if ( declEnd - > link ( ) & & Token : : Match ( declEnd , " (|[|< " ) )
2014-10-16 09:11:09 +02:00
declEnd = declEnd - > link ( ) ;
declEnd = declEnd - > next ( ) ;
}
return declEnd ;
}
2018-06-20 10:00:15 +02:00
void Variable : : evaluate ( const Settings * settings )
2012-05-11 17:56:47 +02:00
{
2020-09-09 16:22:36 +02:00
// Is there initialization in variable declaration
const Token * initTok = mNameToken ? mNameToken - > next ( ) : nullptr ;
while ( initTok & & initTok - > str ( ) = = " [ " )
initTok = initTok - > link ( ) - > next ( ) ;
if ( Token : : Match ( initTok , " =|{ " ) | | ( initTok & & initTok - > isSplittedVarDeclEq ( ) ) )
setFlag ( fIsInit , true ) ;
2020-01-05 15:12:53 +01:00
if ( ! settings )
return ;
2020-01-05 21:10:48 +01:00
const Library * const lib = & settings - > library ;
2018-04-12 20:23:34 +02:00
2021-11-08 20:31:16 +01:00
bool isContainer = false ;
2018-06-16 15:57:16 +02:00
if ( mNameToken )
2021-11-08 20:31:16 +01:00
setFlag ( fIsArray , arrayDimensions ( settings , & isContainer ) ) ;
2015-08-25 21:19:19 +02:00
2018-06-20 10:00:15 +02:00
if ( mTypeStartToken )
2022-08-21 17:11:22 +02:00
setValueType ( ValueType : : parseDecl ( mTypeStartToken , settings , true ) ) ; // TODO: set isCpp
2018-06-20 10:00:15 +02:00
2018-06-16 16:03:36 +02:00
const Token * tok = mTypeStartToken ;
2012-05-15 21:03:43 +02:00
while ( tok & & tok - > previous ( ) & & tok - > previous ( ) - > isName ( ) )
2012-05-11 17:56:47 +02:00
tok = tok - > previous ( ) ;
2018-06-16 16:03:36 +02:00
const Token * end = mTypeEndToken ;
2017-05-07 09:03:30 +02:00
if ( end )
end = end - > next ( ) ;
while ( tok ! = end ) {
2012-05-11 17:56:47 +02:00
if ( tok - > str ( ) = = " static " )
setFlag ( fIsStatic , true ) ;
2012-06-22 11:23:50 +02:00
else if ( tok - > str ( ) = = " extern " )
setFlag ( fIsExtern , true ) ;
2020-04-19 17:29:40 +02:00
else if ( tok - > str ( ) = = " volatile " | | Token : : simpleMatch ( tok , " std :: atomic < " ) )
2016-07-18 12:43:23 +02:00
setFlag ( fIsVolatile , true ) ;
2012-05-11 17:56:47 +02:00
else if ( tok - > str ( ) = = " mutable " )
setFlag ( fIsMutable , true ) ;
2018-06-20 10:00:15 +02:00
else if ( tok - > str ( ) = = " const " )
2012-05-11 17:56:47 +02:00
setFlag ( fIsConst , true ) ;
2021-07-22 07:22:26 +02:00
else if ( tok - > str ( ) = = " constexpr " ) {
setFlag ( fIsConst , true ) ;
setFlag ( fIsStatic , true ) ;
} else if ( tok - > str ( ) = = " * " ) {
2021-11-08 20:31:16 +01:00
setFlag ( fIsPointer , ! isArray ( ) | | ( isContainer & & ! Token : : Match ( tok - > next ( ) , " %name% [ " ) ) | | Token : : Match ( tok - > previous ( ) , " ( * %name% ) " ) ) ;
2012-05-11 17:56:47 +02:00
setFlag ( fIsConst , false ) ; // Points to const, isn't necessarily const itself
2013-04-04 18:47:44 +02:00
} else if ( tok - > str ( ) = = " & " ) {
if ( isReference ( ) )
setFlag ( fIsRValueRef , true ) ;
2012-05-11 17:56:47 +02:00
setFlag ( fIsReference , true ) ;
2013-04-04 18:47:44 +02:00
} else if ( tok - > str ( ) = = " && " ) { // Before simplification, && isn't split up
setFlag ( fIsRValueRef , true ) ;
setFlag ( fIsReference , true ) ; // Set also fIsReference
}
2012-05-14 21:47:02 +02:00
2020-09-06 11:02:22 +02:00
if ( tok - > isAttributeMaybeUnused ( ) ) {
2020-04-12 20:35:54 +02:00
setFlag ( fIsMaybeUnused , true ) ;
}
2013-04-15 22:48:28 +02:00
if ( tok - > str ( ) = = " < " & & tok - > link ( ) )
tok = tok - > link ( ) ;
2012-05-14 21:47:02 +02:00
else
tok = tok - > next ( ) ;
2012-05-11 17:56:47 +02:00
}
2021-07-22 07:22:26 +02:00
while ( Token : : Match ( mTypeStartToken , " static|const|constexpr|volatile %any% " ) )
2018-06-16 16:03:36 +02:00
mTypeStartToken = mTypeStartToken - > next ( ) ;
while ( mTypeEndToken & & mTypeEndToken - > previous ( ) & & Token : : Match ( mTypeEndToken , " const|volatile " ) )
mTypeEndToken = mTypeEndToken - > previous ( ) ;
2012-06-08 18:05:02 +02:00
2018-06-16 16:03:36 +02:00
if ( mTypeStartToken ) {
std : : string strtype = mTypeStartToken - > str ( ) ;
for ( const Token * typeToken = mTypeStartToken ; Token : : Match ( typeToken , " %type% :: %type% " ) ; typeToken = typeToken - > tokAt ( 2 ) )
2015-11-15 17:51:27 +01:00
strtype + = " :: " + typeToken - > strAt ( 2 ) ;
2019-09-04 08:07:30 +02:00
setFlag ( fIsClass , ! lib - > podtype ( strtype ) & & ! mTypeStartToken - > isStandardType ( ) & & ! isEnumType ( ) & & ! isPointer ( ) & & ! isReference ( ) & & strtype ! = " ... " ) ;
2018-06-16 16:03:36 +02:00
setFlag ( fIsStlType , Token : : simpleMatch ( mTypeStartToken , " std :: " ) ) ;
2022-08-20 20:52:10 +02:00
setFlag ( fIsStlString , : : isStlStringType ( mTypeStartToken ) ) ;
2019-04-26 11:30:09 +02:00
setFlag ( fIsSmartPointer , lib - > isSmartPointer ( mTypeStartToken ) ) ;
2014-01-28 15:44:56 +01:00
}
2019-07-23 14:29:02 +02:00
if ( mAccess = = AccessControl : : Argument ) {
2018-06-16 15:57:16 +02:00
tok = mNameToken ;
2012-12-29 08:32:43 +01:00
if ( ! tok ) {
// Argument without name
2018-06-16 16:03:36 +02:00
tok = mTypeEndToken ;
2012-12-29 08:32:43 +01:00
// back up to start of array dimensions
while ( tok & & tok - > str ( ) = = " ] " )
tok = tok - > link ( ) - > previous ( ) ;
// add array dimensions if present
2013-03-12 15:42:00 +01:00
if ( tok & & tok - > next ( ) - > str ( ) = = " [ " )
2021-11-08 20:31:16 +01:00
setFlag ( fIsArray , arrayDimensions ( settings , & isContainer ) ) ;
2012-12-29 08:32:43 +01:00
}
2012-09-06 20:50:46 +02:00
if ( ! tok )
return ;
tok = tok - > next ( ) ;
2012-05-11 17:56:47 +02:00
while ( tok - > str ( ) = = " [ " )
tok = tok - > link ( ) ;
setFlag ( fHasDefault , tok - > str ( ) = = " = " ) ;
}
2013-02-18 06:33:53 +01:00
// check for C++11 member initialization
2018-06-16 20:29:17 +02:00
if ( mScope & & mScope - > isClassOrStruct ( ) ) {
2014-10-12 15:06:07 +02:00
// type var = x or
// type var = {x}
2013-02-18 06:33:53 +01:00
// type var = x; gets simplified to: type var ; var = x ;
2014-10-16 09:11:09 +02:00
Token const * declEnd = declEndToken ( ) ;
2018-06-16 15:57:16 +02:00
if ( ( Token : : Match ( declEnd , " ; %name% = " ) & & declEnd - > strAt ( 1 ) = = mNameToken - > str ( ) ) | |
2014-10-16 09:11:09 +02:00
Token : : Match ( declEnd , " =|{ " ) )
2013-02-18 06:33:53 +01:00
setFlag ( fHasDefault , true ) ;
}
2014-08-09 11:44:55 +02:00
2018-06-16 16:03:36 +02:00
if ( mTypeStartToken ) {
if ( Token : : Match ( mTypeStartToken , " float|double " ) )
2014-08-09 11:44:55 +02:00
setFlag ( fIsFloatType , true ) ;
}
2012-05-11 17:56:47 +02:00
}
2018-06-20 10:00:15 +02:00
void Variable : : setValueType ( const ValueType & valueType )
{
2020-11-16 20:11:26 +01:00
if ( valueType . type = = ValueType : : Type : : UNKNOWN_TYPE ) {
const Token * declType = Token : : findsimplematch ( mTypeStartToken , " decltype ( " , mTypeEndToken ) ;
if ( declType & & ! declType - > next ( ) - > valueType ( ) )
return ;
}
2018-06-20 10:00:15 +02:00
delete mValueType ;
mValueType = new ValueType ( valueType ) ;
if ( ( mValueType - > pointer > 0 ) & & ( ! isArray ( ) | | Token : : Match ( mNameToken - > previous ( ) , " ( * %name% ) " ) ) )
setFlag ( fIsPointer , true ) ;
setFlag ( fIsConst , mValueType - > constness & ( 1U < < mValueType - > pointer ) ) ;
2019-07-09 17:32:19 +02:00
if ( mValueType - > smartPointerType )
setFlag ( fIsSmartPointer , true ) ;
2018-06-20 10:00:15 +02:00
}
2019-07-07 21:52:49 +02:00
const Type * Variable : : smartPointerType ( ) const
{
if ( ! isSmartPointer ( ) )
return nullptr ;
2019-07-09 17:32:19 +02:00
if ( mValueType - > smartPointerType )
return mValueType - > smartPointerType ;
2019-07-07 21:52:49 +02:00
// TODO: Cache result
const Token * ptrType = typeStartToken ( ) ;
while ( Token : : Match ( ptrType , " %name%|:: " ) )
ptrType = ptrType - > next ( ) ;
if ( Token : : Match ( ptrType , " < %name% > " ) )
2019-10-15 19:33:11 +02:00
return ptrType - > scope ( ) - > findType ( ptrType - > next ( ) - > str ( ) ) ;
2019-07-07 21:52:49 +02:00
return nullptr ;
2022-07-19 20:42:54 +02:00
}
const Type * Variable : : iteratorType ( ) const
{
if ( ! mValueType | | mValueType - > type ! = ValueType : : ITERATOR )
return nullptr ;
if ( mValueType - > containerTypeToken )
return mValueType - > containerTypeToken - > type ( ) ;
return nullptr ;
2019-07-07 21:52:49 +02:00
}
2019-11-17 12:08:21 +01:00
std : : string Variable : : getTypeName ( ) const
{
std : : string ret ;
// TODO: For known types, generate the full type name
for ( const Token * typeTok = mTypeStartToken ; Token : : Match ( typeTok , " %name%|:: " ) & & typeTok - > varId ( ) = = 0 ; typeTok = typeTok - > next ( ) )
ret + = typeTok - > str ( ) ;
return ret ;
}
2020-11-01 20:32:42 +01:00
static bool isOperator ( const Token * tokenDef )
{
2020-11-01 15:30:40 +01:00
if ( ! tokenDef )
return false ;
if ( tokenDef - > isOperatorKeyword ( ) )
return true ;
2020-11-01 18:04:13 +01:00
const std : : string & name = tokenDef - > str ( ) ;
2020-11-01 15:30:40 +01:00
return name . size ( ) > 8 & & name . compare ( 0 , 8 , " operator " ) = = 0 & & std : : strchr ( " +-*/%&|~^<>!=[( " , name [ 8 ] ) ;
}
2019-07-24 09:59:01 +02:00
Function : : Function ( const Tokenizer * mTokenizer ,
const Token * tok ,
const Scope * scope ,
const Token * tokDef ,
const Token * tokArgDef )
2018-04-25 12:05:49 +02:00
: tokenDef ( tokDef ) ,
2021-08-07 20:51:18 +02:00
argDef ( tokArgDef ) ,
token ( nullptr ) ,
arg ( nullptr ) ,
retDef ( nullptr ) ,
retType ( nullptr ) ,
functionScope ( nullptr ) ,
nestedIn ( scope ) ,
initArgCount ( 0 ) ,
type ( eFunction ) ,
noexceptArg ( nullptr ) ,
throwArg ( nullptr ) ,
templateDef ( nullptr ) ,
functionPointerUsage ( nullptr ) ,
2022-07-24 10:17:11 +02:00
access ( AccessControl : : Public ) ,
2021-08-07 20:51:18 +02:00
mFlags ( 0 )
2018-04-25 12:05:49 +02:00
{
// operator function
2020-11-01 15:30:40 +01:00
if ( : : isOperator ( tokenDef ) ) {
2018-04-25 12:05:49 +02:00
isOperator ( true ) ;
// 'operator =' is special
if ( tokenDef - > str ( ) = = " operator= " )
type = Function : : eOperatorEqual ;
}
2019-07-05 12:30:42 +02:00
else if ( tokenDef - > str ( ) = = " [ " ) {
type = Function : : eLambda ;
}
2018-04-25 12:05:49 +02:00
// class constructor/destructor
2020-11-24 07:21:37 +01:00
else if ( ( ( tokenDef - > str ( ) = = scope - > className ) | |
( tokenDef - > str ( ) . substr ( 0 , scope - > className . size ( ) ) = = scope - > className & &
tokenDef - > str ( ) . size ( ) > scope - > className . size ( ) + 1 & &
tokenDef - > str ( ) [ scope - > className . size ( ) + 1 ] = = ' < ' ) ) & &
2020-11-24 22:03:30 +01:00
scope - > type ! = Scope : : ScopeType : : eNamespace ) {
2018-04-25 12:05:49 +02:00
// destructor
if ( tokenDef - > previous ( ) - > str ( ) = = " ~ " )
type = Function : : eDestructor ;
// constructor of any kind
else
type = Function : : eConstructor ;
2022-01-17 20:51:23 +01:00
isExplicit ( tokenDef - > strAt ( - 1 ) = = " explicit " | | tokenDef - > strAt ( - 2 ) = = " explicit " ) ;
2018-04-25 12:05:49 +02:00
}
2020-11-03 17:52:38 +01:00
const Token * tok1 = setFlags ( tok , scope ) ;
2018-04-25 12:05:49 +02:00
// find the return type
2019-07-05 12:30:42 +02:00
if ( ! isConstructor ( ) & & ! isDestructor ( ) & & ! isLambda ( ) ) {
2018-12-13 06:34:10 +01:00
// @todo auto type deduction should be checked
// @todo attributes and exception specification can also precede trailing return type
if ( Token : : Match ( argDef - > link ( ) - > next ( ) , " const|volatile| &|&&| . " ) ) { // Trailing return type
hasTrailingReturnType ( true ) ;
if ( argDef - > link ( ) - > strAt ( 1 ) = = " . " )
retDef = argDef - > link ( ) - > tokAt ( 2 ) ;
else if ( argDef - > link ( ) - > strAt ( 2 ) = = " . " )
retDef = argDef - > link ( ) - > tokAt ( 3 ) ;
else if ( argDef - > link ( ) - > strAt ( 3 ) = = " . " )
retDef = argDef - > link ( ) - > tokAt ( 4 ) ;
} else {
2018-04-25 12:05:49 +02:00
if ( tok1 - > str ( ) = = " > " )
tok1 = tok1 - > next ( ) ;
while ( Token : : Match ( tok1 , " extern|virtual|static|friend|struct|union|enum " ) )
tok1 = tok1 - > next ( ) ;
retDef = tok1 ;
}
}
const Token * end = argDef - > link ( ) ;
2018-04-27 10:35:11 +02:00
// parse function attributes..
2018-04-25 14:35:09 +02:00
tok = end - > next ( ) ;
while ( tok ) {
2018-04-25 12:05:49 +02:00
if ( tok - > str ( ) = = " const " )
2018-04-25 14:35:09 +02:00
isConst ( true ) ;
else if ( tok - > str ( ) = = " & " )
2018-04-25 12:05:49 +02:00
hasLvalRefQualifier ( true ) ;
2018-04-25 14:35:09 +02:00
else if ( tok - > str ( ) = = " && " )
2018-04-25 12:05:49 +02:00
hasRvalRefQualifier ( true ) ;
2018-04-27 14:57:43 +02:00
else if ( tok - > str ( ) = = " override " )
setFlag ( fHasOverrideSpecifier , true ) ;
else if ( tok - > str ( ) = = " final " )
setFlag ( fHasFinalSpecifier , true ) ;
2018-05-10 07:40:01 +02:00
else if ( tok - > str ( ) = = " volatile " )
isVolatile ( true ) ;
2018-04-25 14:35:09 +02:00
else if ( tok - > str ( ) = = " noexcept " ) {
2018-04-25 12:05:49 +02:00
isNoExcept ( ! Token : : simpleMatch ( tok - > next ( ) , " ( false ) " ) ) ;
2018-05-05 08:31:56 +02:00
if ( tok - > next ( ) - > str ( ) = = " ( " )
tok = tok - > linkAt ( 1 ) ;
2018-04-25 12:05:49 +02:00
} else if ( Token : : simpleMatch ( tok , " throw ( " ) ) {
isThrow ( true ) ;
if ( tok - > strAt ( 2 ) ! = " ) " )
2018-04-25 14:35:09 +02:00
throwArg = tok - > next ( ) ;
tok = tok - > linkAt ( 1 ) ;
} else if ( Token : : Match ( tok , " = 0|default|delete ; " ) ) {
2018-04-25 12:05:49 +02:00
const std : : string & modifier = tok - > strAt ( 1 ) ;
isPure ( modifier = = " 0 " ) ;
isDefault ( modifier = = " default " ) ;
isDelete ( modifier = = " delete " ) ;
2018-12-13 06:34:10 +01:00
} else if ( tok - > str ( ) = = " . " ) { // trailing return type
// skip over return type
while ( tok & & ! Token : : Match ( tok - > next ( ) , " ;|{|override|final " ) )
tok = tok - > next ( ) ;
2018-04-25 14:35:09 +02:00
} else
break ;
2018-12-13 06:34:10 +01:00
if ( tok )
tok = tok - > next ( ) ;
2018-04-25 14:35:09 +02:00
}
2018-06-16 16:10:28 +02:00
if ( mTokenizer - > isFunctionHead ( end , " :{ " ) ) {
2018-04-25 12:05:49 +02:00
// assume implementation is inline (definition and implementation same)
token = tokenDef ;
arg = argDef ;
isInline ( true ) ;
hasBody ( true ) ;
}
}
2021-04-30 16:47:02 +02:00
Function : : Function ( const Token * tokenDef , const std : : string & clangType )
: tokenDef ( tokenDef ) ,
2021-08-07 20:51:18 +02:00
argDef ( nullptr ) ,
token ( nullptr ) ,
arg ( nullptr ) ,
retDef ( nullptr ) ,
retType ( nullptr ) ,
functionScope ( nullptr ) ,
nestedIn ( nullptr ) ,
initArgCount ( 0 ) ,
type ( eFunction ) ,
noexceptArg ( nullptr ) ,
throwArg ( nullptr ) ,
templateDef ( nullptr ) ,
functionPointerUsage ( nullptr ) ,
2022-07-24 10:17:11 +02:00
access ( AccessControl : : Public ) ,
2021-08-07 20:51:18 +02:00
mFlags ( 0 )
2021-04-30 16:47:02 +02:00
{
// operator function
if ( : : isOperator ( tokenDef ) ) {
isOperator ( true ) ;
// 'operator =' is special
if ( tokenDef - > str ( ) = = " operator= " )
type = Function : : eOperatorEqual ;
}
setFlags ( tokenDef , tokenDef - > scope ( ) ) ;
2021-09-28 20:34:21 +02:00
if ( endsWith ( clangType , " const " ) )
2021-04-30 16:47:02 +02:00
isConst ( true ) ;
}
2020-11-03 17:52:38 +01:00
const Token * Function : : setFlags ( const Token * tok1 , const Scope * scope )
{
2021-07-18 21:18:07 +02:00
if ( tok1 - > isInline ( ) )
isInlineKeyword ( true ) ;
2020-11-03 17:52:38 +01:00
// look for end of previous statement
while ( tok1 - > previous ( ) & & ! Token : : Match ( tok1 - > previous ( ) , " ;|}|{|public:|protected:|private: " ) ) {
tok1 = tok1 - > previous ( ) ;
2021-07-18 21:18:07 +02:00
if ( tok1 - > isInline ( ) )
isInlineKeyword ( true ) ;
2020-11-03 17:52:38 +01:00
// extern function
2022-07-14 20:59:58 +02:00
if ( tok1 - > isExternC ( ) | | tok1 - > str ( ) = = " extern " ) {
2020-11-03 17:52:38 +01:00
isExtern ( true ) ;
}
// virtual function
else if ( tok1 - > str ( ) = = " virtual " ) {
hasVirtualSpecifier ( true ) ;
}
// static function
else if ( tok1 - > str ( ) = = " static " ) {
isStatic ( true ) ;
if ( scope - > type = = Scope : : eNamespace | | scope - > type = = Scope : : eGlobal )
isStaticLocal ( true ) ;
}
// friend function
else if ( tok1 - > str ( ) = = " friend " ) {
isFriend ( true ) ;
}
2021-07-22 07:22:26 +02:00
// constexpr function
else if ( tok1 - > str ( ) = = " constexpr " ) {
isConstexpr ( true ) ;
}
2022-01-16 12:33:31 +01:00
// decltype
else if ( tok1 - > str ( ) = = " ) " & & Token : : simpleMatch ( tok1 - > link ( ) - > previous ( ) , " decltype ( " ) ) {
tok1 = tok1 - > link ( ) - > previous ( ) ;
}
2022-09-26 18:20:42 +02:00
else if ( tok1 - > link ( ) & & tok1 - > str ( ) = = " > " ) {
// Function template
if ( Token : : simpleMatch ( tok1 - > link ( ) - > previous ( ) , " template < " ) ) {
templateDef = tok1 - > link ( ) - > previous ( ) ;
break ;
}
tok1 = tok1 - > link ( ) ;
2020-11-03 17:52:38 +01:00
}
}
return tok1 ;
2020-01-05 15:12:53 +01:00
}
2020-04-27 09:08:50 +02:00
std : : string Function : : fullName ( ) const
{
std : : string ret = name ( ) ;
for ( const Scope * s = nestedIn ; s ; s = s - > nestedIn ) {
if ( ! s - > className . empty ( ) )
ret = s - > className + " :: " + ret ;
}
ret + = " ( " ;
2020-05-10 22:16:58 +02:00
for ( const Variable & a : argumentList )
ret + = ( a . index ( ) = = 0 ? " " : " , " ) + a . name ( ) ;
2020-04-27 09:08:50 +02:00
return ret + " ) " ;
}
2020-01-05 15:12:53 +01:00
2019-10-10 20:25:09 +02:00
static std : : string qualifiedName ( const Scope * scope )
{
std : : string name = scope - > className ;
while ( scope - > nestedIn ) {
if ( ! scope - > nestedIn - > className . empty ( ) )
name = ( scope - > nestedIn - > className + " :: " ) + name ;
scope = scope - > nestedIn ;
}
return name ;
}
static bool usingNamespace ( const Scope * scope , const Token * first , const Token * second , int & offset )
{
2020-12-18 07:46:01 +01:00
// check if qualifications match first before checking if using is needed
const Token * tok1 = first ;
const Token * tok2 = second ;
bool match = false ;
while ( Token : : Match ( tok1 , " %type% :: %type% " ) & & Token : : Match ( tok2 , " %type% :: %type% " ) ) {
if ( tok1 - > str ( ) = = tok2 - > str ( ) ) {
tok1 = tok1 - > tokAt ( 2 ) ;
tok2 = tok2 - > tokAt ( 2 ) ;
match = true ;
} else {
match = false ;
break ;
}
}
if ( match )
return false ;
2019-10-10 20:25:09 +02:00
offset = 0 ;
std : : string name = first - > str ( ) ;
while ( Token : : Match ( first , " %type% :: %type% " ) ) {
if ( offset )
name + = ( " :: " + first - > str ( ) ) ;
offset + = 2 ;
first = first - > tokAt ( 2 ) ;
if ( first - > str ( ) = = second - > str ( ) ) {
break ;
}
}
if ( offset ) {
while ( scope ) {
for ( const auto & info : scope - > usingList ) {
2019-10-12 11:39:14 +02:00
if ( info . scope ) {
if ( name = = qualifiedName ( info . scope ) )
return true ;
}
// no scope so get name from using
else {
const Token * start = info . start - > tokAt ( 2 ) ;
std : : string nsName ;
while ( start & & start - > str ( ) ! = " ; " ) {
if ( ! nsName . empty ( ) )
nsName + = " " ;
nsName + = start - > str ( ) ;
start = start - > next ( ) ;
}
if ( nsName = = name )
return true ;
}
2019-10-10 20:25:09 +02:00
}
scope = scope - > nestedIn ;
}
}
return false ;
}
2021-01-18 19:01:04 +01:00
static bool typesMatch (
const Scope * first_scope ,
const Token * first_token ,
const Scope * second_scope ,
const Token * second_token ,
const Token * * new_first ,
const Token * * new_second )
{
// get first type
const Type * first_type = first_scope - > check - > findType ( first_token , first_scope ) ;
if ( first_type ) {
// get second type
const Type * second_type = second_scope - > check - > findType ( second_token , second_scope ) ;
// check if types match
if ( first_type = = second_type ) {
const Token * tok1 = first_token ;
while ( tok1 & & tok1 - > str ( ) ! = first_type - > name ( ) )
tok1 = tok1 - > next ( ) ;
const Token * tok2 = second_token ;
while ( tok2 & & tok2 - > str ( ) ! = second_type - > name ( ) )
tok2 = tok2 - > next ( ) ;
// update parser token positions
if ( tok1 & & tok2 ) {
2021-01-21 19:47:51 +01:00
* new_first = tok1 - > previous ( ) ;
* new_second = tok2 - > previous ( ) ;
2021-01-18 19:01:04 +01:00
return true ;
}
}
}
return false ;
}
bool Function : : argsMatch ( const Scope * scope , const Token * first , const Token * second , const std : : string & path , nonneg int path_length ) const
2010-11-13 08:08:45 +01:00
{
2012-11-26 16:34:44 +01:00
const bool isCPP = scope - > check - > isCPP ( ) ;
2014-09-01 17:01:05 +02:00
if ( ! isCPP ) // C does not support overloads
return true ;
2012-11-26 16:34:44 +01:00
2019-07-22 11:25:51 +02:00
int arg_path_length = path_length ;
2019-10-10 20:25:09 +02:00
int offset = 0 ;
2021-01-06 17:29:23 +01:00
int openParen = 0 ;
2018-05-01 07:32:19 +02:00
2021-05-24 19:32:15 +02:00
// check for () == (void) and (void) == ()
if ( ( Token : : simpleMatch ( first , " ( ) " ) & & Token : : simpleMatch ( second , " ( void ) " ) ) | |
( Token : : simpleMatch ( first , " ( void ) " ) & & Token : : simpleMatch ( second , " ( ) " ) ) )
return true ;
2013-03-14 19:11:29 +01:00
while ( first - > str ( ) = = second - > str ( ) & &
first - > isLong ( ) = = second - > isLong ( ) & &
first - > isUnsigned ( ) = = second - > isUnsigned ( ) ) {
2021-01-06 17:29:23 +01:00
if ( first - > str ( ) = = " ( " )
openParen + + ;
2021-01-28 12:38:36 +01:00
// at end of argument list
else if ( first - > str ( ) = = " ) " ) {
if ( openParen = = 1 )
return true ;
else
- - openParen ;
}
2018-11-09 15:54:17 +01:00
// skip optional type information
if ( Token : : Match ( first - > next ( ) , " struct|enum|union|class " ) )
2018-11-09 06:11:48 +01:00
first = first - > next ( ) ;
2018-11-09 15:54:17 +01:00
if ( Token : : Match ( second - > next ( ) , " struct|enum|union|class " ) )
2018-11-09 06:11:48 +01:00
second = second - > next ( ) ;
// skip const on type passed by value
if ( Token : : Match ( first - > next ( ) , " const %type% %name%|,|) " ) & &
! Token : : Match ( first - > next ( ) , " const %type% %name%| [ " ) )
first = first - > next ( ) ;
if ( Token : : Match ( second - > next ( ) , " const %type% %name%|,|) " ) & &
! Token : : Match ( second - > next ( ) , " const %type% %name%| [ " ) )
second = second - > next ( ) ;
2010-11-13 08:08:45 +01:00
// skip default value assignment
2011-10-13 20:53:06 +02:00
else if ( first - > next ( ) - > str ( ) = = " = " ) {
2012-02-11 12:26:48 +01:00
first = first - > nextArgument ( ) ;
2013-05-18 18:33:24 +02:00
if ( first )
first = first - > tokAt ( - 2 ) ;
2012-02-11 12:26:48 +01:00
if ( second - > next ( ) - > str ( ) = = " = " ) {
second = second - > nextArgument ( ) ;
2013-05-18 18:33:24 +02:00
if ( second )
second = second - > tokAt ( - 2 ) ;
2012-02-11 12:26:48 +01:00
if ( ! first | | ! second ) { // End of argument list (first or second)
2012-04-18 13:00:34 +02:00
return ! first & & ! second ;
2012-02-11 12:26:48 +01:00
}
} else if ( ! first ) { // End of argument list (first)
2016-08-09 14:02:06 +02:00
return ! second - > nextArgument ( ) ; // End of argument list (second)
2012-02-11 12:26:48 +01:00
}
2013-05-18 18:33:24 +02:00
} else if ( second - > next ( ) - > str ( ) = = " = " ) {
second = second - > nextArgument ( ) ;
if ( second )
second = second - > tokAt ( - 2 ) ;
2015-02-19 15:16:38 +01:00
if ( ! second ) { // End of argument list (second)
return false ;
2013-05-18 18:33:24 +02:00
}
2011-08-26 01:13:53 +02:00
}
2010-11-13 08:08:45 +01:00
// definition missing variable name
2015-08-16 14:22:46 +02:00
else if ( ( first - > next ( ) - > str ( ) = = " , " & & second - > next ( ) - > str ( ) ! = " , " ) | |
2019-11-03 18:42:04 +01:00
( Token : : Match ( first , " !!( ) " ) & & second - > next ( ) - > str ( ) ! = " ) " ) ) {
2010-11-13 08:08:45 +01:00
second = second - > next ( ) ;
2013-05-18 18:33:24 +02:00
// skip default value assignment
if ( second - > next ( ) - > str ( ) = = " = " ) {
2015-08-16 14:22:46 +02:00
do {
2013-05-18 18:33:24 +02:00
second = second - > next ( ) ;
2015-08-16 14:22:46 +02:00
} while ( ! Token : : Match ( second - > next ( ) , " ,|) " ) ) ;
2013-05-18 18:33:24 +02:00
}
} else if ( first - > next ( ) - > str ( ) = = " [ " & & second - > next ( ) - > str ( ) ! = " [ " )
2012-12-28 16:28:29 +01:00
second = second - > next ( ) ;
2010-11-13 08:08:45 +01:00
// function missing variable name
2015-08-16 14:22:46 +02:00
else if ( ( second - > next ( ) - > str ( ) = = " , " & & first - > next ( ) - > str ( ) ! = " , " ) | |
2019-11-03 18:42:04 +01:00
( Token : : Match ( second , " !!( ) " ) & & first - > next ( ) - > str ( ) ! = " ) " ) ) {
2010-11-13 08:08:45 +01:00
first = first - > next ( ) ;
2013-05-18 18:33:24 +02:00
// skip default value assignment
if ( first - > next ( ) - > str ( ) = = " = " ) {
2015-08-16 14:22:46 +02:00
do {
2013-05-18 18:33:24 +02:00
first = first - > next ( ) ;
2015-08-16 14:22:46 +02:00
} while ( ! Token : : Match ( first - > next ( ) , " ,|) " ) ) ;
2013-05-18 18:33:24 +02:00
}
} else if ( second - > next ( ) - > str ( ) = = " [ " & & first - > next ( ) - > str ( ) ! = " [ " )
2012-12-28 16:28:29 +01:00
first = first - > next ( ) ;
2010-11-13 08:08:45 +01:00
2022-03-11 21:44:13 +01:00
// unnamed parameters
else if ( Token : : Match ( first , " (|, %type% ,|) " ) && Token::Match(second, " ( | , % type % , | ) " )) {
if ( first - > next ( ) - > expressionString ( ) ! = second - > next ( ) - > expressionString ( ) )
break ;
first = first - > next ( ) ;
second = second - > next ( ) ;
continue ;
}
2010-11-13 08:08:45 +01:00
// argument list has different number of arguments
2021-01-28 12:38:36 +01:00
else if ( openParen = = 1 & & second - > str ( ) = = " ) " & & first - > str ( ) ! = " ) " )
2010-11-13 08:08:45 +01:00
break ;
2016-08-20 17:56:48 +02:00
// ckeck for type * x == type x[]
else if ( Token : : Match ( first - > next ( ) , " * %name%| ,|)|= " ) & &
Token : : Match ( second - > next ( ) , " %name%| [ ] ,|) " ) ) {
do {
first = first - > next ( ) ;
} while ( ! Token : : Match ( first - > next ( ) , " ,|) " ) ) ;
do {
second = second - > next ( ) ;
} while ( ! Token : : Match ( second - > next ( ) , " ,|) " ) ) ;
}
2016-08-20 07:43:15 +02:00
// const after *
2021-01-05 22:07:53 +01:00
else if ( first - > next ( ) - > str ( ) = = " * " & & second - > next ( ) - > str ( ) = = " * " & &
( ( first - > strAt ( 2 ) ! = " const " & & second - > strAt ( 2 ) = = " const " ) | |
( first - > strAt ( 2 ) = = " const " & & second - > strAt ( 2 ) ! = " const " ) ) ) {
if ( first - > strAt ( 2 ) ! = " const " ) {
first = first - > next ( ) ;
second = second - > tokAt ( 2 ) ;
} else {
first = first - > tokAt ( 2 ) ;
second = second - > next ( ) ;
}
2016-08-20 07:43:15 +02:00
}
2010-11-13 08:08:45 +01:00
// variable names are different
2016-08-09 14:02:06 +02:00
else if ( ( Token : : Match ( first - > next ( ) , " %name% ,|)|=|[ " ) & &
Token : : Match ( second - > next ( ) , " %name% ,|)|[ " ) ) & &
2011-10-13 20:53:06 +02:00
( first - > next ( ) - > str ( ) ! = second - > next ( ) - > str ( ) ) ) {
2010-11-13 08:08:45 +01:00
// skip variable names
first = first - > next ( ) ;
second = second - > next ( ) ;
2016-03-22 14:10:20 +01:00
// skip default value assignment
if ( first - > next ( ) - > str ( ) = = " = " ) {
do {
first = first - > next ( ) ;
} while ( ! Token : : Match ( first - > next ( ) , " ,|) " ) ) ;
}
2010-11-13 08:08:45 +01:00
}
2019-10-10 20:25:09 +02:00
// using namespace
else if ( usingNamespace ( scope , first - > next ( ) , second - > next ( ) , offset ) )
first = first - > tokAt ( offset ) ;
2021-01-18 19:01:04 +01:00
// same type with different qualification
else if ( typesMatch ( scope , first - > next ( ) , nestedIn , second - > next ( ) , & first , & second ) )
;
2010-11-13 08:08:45 +01:00
// variable with class path
2018-05-01 07:32:19 +02:00
else if ( arg_path_length & & Token : : Match ( first - > next ( ) , " %name% " ) & & first - > strAt ( 1 ) ! = " const " ) {
std : : string param = path ;
2010-11-13 08:08:45 +01:00
2020-05-26 20:13:56 +02:00
if ( Token : : simpleMatch ( second - > next ( ) , param . c_str ( ) , param . size ( ) ) ) {
2021-01-06 17:29:23 +01:00
// check for redundant qualification before skipping it
if ( ! Token : : simpleMatch ( first - > next ( ) , param . c_str ( ) , param . size ( ) ) ) {
second = second - > tokAt ( int ( arg_path_length ) ) ;
arg_path_length = 0 ;
}
2018-05-01 07:32:19 +02:00
}
// nested or base class variable
else if ( arg_path_length < = 2 & & Token : : Match ( first - > next ( ) , " %name% " ) & &
( Token : : Match ( second - > next ( ) , " %name% :: %name% " ) | |
( Token : : Match ( second - > next ( ) , " %name% < " ) & &
Token : : Match ( second - > linkAt ( 1 ) , " > :: %name% " ) ) ) & &
( ( second - > next ( ) - > str ( ) = = scope - > className ) | |
2022-04-05 07:34:06 +02:00
( scope - > nestedIn & & second - > next ( ) - > str ( ) = = scope - > nestedIn - > className ) | |
2018-05-01 07:32:19 +02:00
( scope - > definedType & & scope - > definedType - > isDerivedFrom ( second - > next ( ) - > str ( ) ) ) ) & &
( first - > next ( ) - > str ( ) = = second - > strAt ( 3 ) ) ) {
if ( Token : : Match ( second - > next ( ) , " %name% < " ) )
second = second - > linkAt ( 1 ) - > next ( ) ;
else
second = second - > tokAt ( 2 ) ;
}
// remove class name
2018-11-05 06:55:30 +01:00
else if ( arg_path_length > 2 & & first - > strAt ( 1 ) ! = second - > strAt ( 1 ) ) {
2012-04-18 13:00:34 +02:00
std : : string short_path = path ;
2018-05-01 07:32:19 +02:00
unsigned int short_path_length = arg_path_length ;
2010-11-13 08:08:45 +01:00
// remove last " :: "
short_path . resize ( short_path . size ( ) - 4 ) ;
2018-05-01 07:32:19 +02:00
short_path_length - - ;
2010-11-13 08:08:45 +01:00
// remove last name
2018-05-01 07:32:19 +02:00
std : : string : : size_type lastSpace = short_path . find_last_of ( ' ' ) ;
if ( lastSpace ! = std : : string : : npos ) {
2015-08-16 14:22:46 +02:00
short_path . resize ( lastSpace + 1 ) ;
2018-05-01 07:32:19 +02:00
short_path_length - - ;
if ( short_path [ short_path . size ( ) - 1 ] = = ' > ' ) {
short_path . resize ( short_path . size ( ) - 3 ) ;
while ( short_path [ short_path . size ( ) - 1 ] = = ' < ' ) {
lastSpace = short_path . find_last_of ( ' ' ) ;
short_path . resize ( lastSpace + 1 ) ;
short_path_length - - ;
}
}
}
2010-11-13 08:08:45 +01:00
2018-05-01 07:32:19 +02:00
param = short_path ;
2020-05-26 20:13:56 +02:00
if ( Token : : simpleMatch ( second - > next ( ) , param . c_str ( ) , param . size ( ) ) ) {
2018-05-01 07:32:19 +02:00
second = second - > tokAt ( int ( short_path_length ) ) ;
arg_path_length = 0 ;
2010-11-13 08:08:45 +01:00
}
}
}
first = first - > next ( ) ;
second = second - > next ( ) ;
2012-11-26 16:34:44 +01:00
2018-05-01 07:32:19 +02:00
// reset path length
if ( first - > str ( ) = = " , " | | second - > str ( ) = = " , " )
arg_path_length = path_length ;
2010-11-13 08:08:45 +01:00
}
2012-04-18 13:00:34 +02:00
return false ;
2010-11-13 08:08:45 +01:00
}
2021-04-30 17:47:08 +02:00
static bool isUnknownType ( const Token * start , const Token * end )
{
while ( Token : : Match ( start , " const|volatile " ) )
start = start - > next ( ) ;
2021-05-01 07:35:03 +02:00
start = skipScopeIdentifiers ( start ) ;
2021-04-30 17:47:08 +02:00
if ( start - > tokAt ( 1 ) = = end & & ! start - > type ( ) & & ! start - > isStandardType ( ) )
return true ;
// TODO: Try to deduce the type of the expression
if ( Token : : Match ( start , " decltype|typeof " ) )
return true ;
return false ;
}
2022-09-26 18:20:42 +02:00
static const Token * getEnableIfReturnType ( const Token * start )
{
if ( ! start )
return nullptr ;
for ( const Token * tok = start - > next ( ) ; precedes ( tok , start - > link ( ) ) ; tok = tok - > next ( ) ) {
if ( tok - > link ( ) & & Token : : Match ( tok , " (|[|{|< " ) ) {
tok = tok - > link ( ) ;
continue ;
}
if ( Token : : simpleMatch ( tok , " , " ) )
return tok - > next ( ) ;
}
return nullptr ;
}
template < class Predicate >
static bool checkReturns ( const Function * function , bool unknown , bool emptyEnableIf , Predicate pred )
2021-04-30 17:47:08 +02:00
{
if ( ! function )
return false ;
2022-09-26 18:20:42 +02:00
if ( function - > type ! = Function : : eFunction & & function - > type ! = Function : : eOperatorEqual )
2021-04-30 17:47:08 +02:00
return false ;
2022-09-26 18:20:42 +02:00
const Token * defStart = function - > retDef ;
if ( ! defStart )
return unknown ;
2022-10-06 20:12:07 +02:00
const Token * defEnd = function - > returnDefEnd ( ) ;
2022-09-26 18:20:42 +02:00
if ( ! defEnd )
return unknown ;
if ( defEnd = = defStart )
return unknown ;
if ( pred ( defStart , defEnd ) )
return true ;
if ( Token : : Match ( defEnd - > tokAt ( - 1 ) , " *|&|&& " ) )
return false ;
// void STDCALL foo()
while ( defEnd - > previous ( ) ! = defStart & & Token : : Match ( defEnd - > tokAt ( - 2 ) , " %name%|> %name% " ) & &
! Token : : Match ( defEnd - > tokAt ( - 2 ) , " const|volatile " ) )
defEnd = defEnd - > previous ( ) ;
// enable_if
const Token * enableIfEnd = nullptr ;
if ( Token : : simpleMatch ( defEnd - > previous ( ) , " > " ) )
enableIfEnd = defEnd - > previous ( ) ;
else if ( Token : : simpleMatch ( defEnd - > tokAt ( - 3 ) , " > :: type " ) )
enableIfEnd = defEnd - > tokAt ( - 3 ) ;
if ( enableIfEnd & & enableIfEnd - > link ( ) & &
Token : : Match ( enableIfEnd - > link ( ) - > previous ( ) , " enable_if|enable_if_t|EnableIf " ) ) {
if ( const Token * start = getEnableIfReturnType ( enableIfEnd - > link ( ) ) ) {
defStart = start ;
defEnd = enableIfEnd ;
} else {
return emptyEnableIf ;
}
}
assert ( defEnd ! = defStart ) ;
if ( pred ( defStart , defEnd ) )
2021-04-30 17:47:08 +02:00
return true ;
2022-09-26 18:20:42 +02:00
if ( isUnknownType ( defStart , defEnd ) )
2021-04-30 17:47:08 +02:00
return unknown ;
return false ;
}
2022-09-26 18:20:42 +02:00
bool Function : : returnsConst ( const Function * function , bool unknown )
{
return checkReturns ( function , unknown , false , [ ] ( const Token * defStart , const Token * defEnd ) {
return Token : : findsimplematch ( defStart , " const " , defEnd ) ;
} ) ;
}
2019-10-08 09:28:39 +02:00
bool Function : : returnsReference ( const Function * function , bool unknown )
2019-01-23 07:29:16 +01:00
{
2022-09-26 18:20:42 +02:00
return checkReturns ( function , unknown , false , [ ] ( UNUSED const Token * defStart , const Token * defEnd ) {
return Token : : simpleMatch ( defEnd - > previous ( ) , " & " ) ;
} ) ;
2019-01-23 07:29:16 +01:00
}
2021-07-08 13:50:26 +02:00
bool Function : : returnsVoid ( const Function * function , bool unknown )
{
2022-09-26 18:20:42 +02:00
return checkReturns ( function , unknown , true , [ ] ( UNUSED const Token * defStart , const Token * defEnd ) {
return Token : : simpleMatch ( defEnd - > previous ( ) , " void " ) ;
} ) ;
2021-07-08 13:50:26 +02:00
}
2020-05-31 10:10:10 +02:00
std : : vector < const Token * > Function : : findReturns ( const Function * f )
{
std : : vector < const Token * > result ;
if ( ! f )
return result ;
const Scope * scope = f - > functionScope ;
if ( ! scope )
return result ;
for ( const Token * tok = scope - > bodyStart - > next ( ) ; tok & & tok ! = scope - > bodyEnd ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " { " & & tok - > scope ( ) & &
( tok - > scope ( ) - > type = = Scope : : eLambda | | tok - > scope ( ) - > type = = Scope : : eClass ) ) {
tok = tok - > link ( ) ;
continue ;
}
if ( Token : : simpleMatch ( tok - > astParent ( ) , " return " ) ) {
result . push_back ( tok ) ;
}
// Skip lambda functions since the scope may not be set correctly
const Token * lambdaEndToken = findLambdaEndToken ( tok ) ;
if ( lambdaEndToken ) {
tok = lambdaEndToken ;
}
}
return result ;
}
2016-11-20 15:14:49 +01:00
const Token * Function : : constructorMemberInitialization ( ) const
{
2021-02-19 08:21:26 +01:00
if ( ! isConstructor ( ) | | ! arg )
2016-11-20 15:14:49 +01:00
return nullptr ;
2021-02-19 08:21:26 +01:00
if ( Token : : simpleMatch ( arg - > link ( ) , " ) : " ) )
return arg - > link ( ) - > next ( ) ;
if ( Token : : simpleMatch ( arg - > link ( ) , " ) noexcept ( " ) & & arg - > link ( ) - > linkAt ( 2 ) - > strAt ( 1 ) = = " : " )
return arg - > link ( ) - > linkAt ( 2 ) - > next ( ) ;
2016-11-20 15:14:49 +01:00
return nullptr ;
}
2019-07-10 16:59:05 +02:00
bool Function : : isSafe ( const Settings * settings ) const
{
2019-07-25 17:28:32 +02:00
if ( settings - > safeChecks . externalFunctions ) {
2019-07-25 20:52:24 +02:00
if ( nestedIn - > type = = Scope : : ScopeType : : eNamespace & & token - > fileIndex ( ) ! = 0 )
return true ;
if ( nestedIn - > type = = Scope : : ScopeType : : eGlobal & & ( token - > fileIndex ( ) ! = 0 | | ! isStatic ( ) ) )
return true ;
2019-07-24 08:23:05 +02:00
}
2019-07-25 17:28:32 +02:00
if ( settings - > safeChecks . internalFunctions ) {
2019-07-25 20:52:24 +02:00
if ( nestedIn - > type = = Scope : : ScopeType : : eNamespace & & token - > fileIndex ( ) = = 0 )
return true ;
if ( nestedIn - > type = = Scope : : ScopeType : : eGlobal & & ( token - > fileIndex ( ) = = 0 | | isStatic ( ) ) )
return true ;
2019-07-25 17:28:32 +02:00
}
2019-07-25 20:52:24 +02:00
if ( settings - > safeChecks . classes & & access = = AccessControl : : Public & & ( nestedIn - > type = = Scope : : ScopeType : : eClass | | nestedIn - > type = = Scope : : ScopeType : : eStruct ) )
2019-07-25 17:28:32 +02:00
return true ;
2019-07-24 08:23:05 +02:00
2019-07-23 11:54:38 +02:00
return false ;
2019-07-10 16:59:05 +02:00
}
2012-02-11 12:26:48 +01:00
Function * SymbolDatabase : : addGlobalFunction ( Scope * & scope , const Token * & tok , const Token * argStart , const Token * funcStart )
2012-03-23 17:59:51 +01:00
{
2015-12-06 08:14:04 +01:00
Function * function = nullptr ;
2019-07-05 12:30:42 +02:00
// Lambda functions are always unique
if ( tok - > str ( ) ! = " [ " ) {
2022-06-08 16:58:57 +02:00
auto range = scope - > functionMap . equal_range ( tok - > str ( ) ) ;
for ( std : : multimap < std : : string , const Function * > : : const_iterator it = range . first ; it ! = range . second ; + + it ) {
const Function * f = it - > second ;
2019-07-05 12:30:42 +02:00
if ( f - > hasBody ( ) )
continue ;
2021-01-18 19:01:04 +01:00
if ( f - > argsMatch ( scope , f - > argDef , argStart , emptyString , 0 ) ) {
2022-06-08 16:58:57 +02:00
function = const_cast < Function * > ( it - > second ) ;
2019-07-05 12:30:42 +02:00
break ;
}
2014-03-14 05:40:17 +01:00
}
2012-03-23 17:59:51 +01:00
}
2012-10-14 17:30:37 +02:00
2012-03-23 17:59:51 +01:00
if ( ! function )
2013-08-31 18:58:55 +02:00
function = addGlobalFunctionDecl ( scope , tok , argStart , funcStart ) ;
2012-03-23 17:59:51 +01:00
function - > arg = argStart ;
function - > token = funcStart ;
2015-01-08 05:45:31 +01:00
function - > hasBody ( true ) ;
2012-03-23 17:59:51 +01:00
addNewFunction ( & scope , & tok ) ;
if ( scope ) {
2012-04-25 20:52:59 +02:00
scope - > function = function ;
2012-04-27 21:51:13 +02:00
function - > functionScope = scope ;
2012-03-23 17:59:51 +01:00
return function ;
}
2015-12-06 08:14:04 +01:00
return nullptr ;
2012-03-23 17:59:51 +01:00
}
2013-08-31 18:58:55 +02:00
Function * SymbolDatabase : : addGlobalFunctionDecl ( Scope * & scope , const Token * tok , const Token * argStart , const Token * funcStart )
2012-02-11 12:26:48 +01:00
{
2018-06-16 16:10:28 +02:00
Function function ( mTokenizer , tok , scope , funcStart , argStart ) ;
2022-09-29 21:47:17 +02:00
scope - > addFunction ( std : : move ( function ) ) ;
2012-03-23 17:59:51 +01:00
return & scope - > functionList . back ( ) ;
2012-02-11 12:26:48 +01:00
}
void SymbolDatabase : : addClassFunction ( Scope * * scope , const Token * * tok , const Token * argStart )
2010-11-13 08:08:45 +01:00
{
2012-01-22 19:34:53 +01:00
const bool destructor ( ( * tok ) - > previous ( ) - > str ( ) = = " ~ " ) ;
2016-01-02 18:53:51 +01:00
const bool has_const ( argStart - > link ( ) - > strAt ( 1 ) = = " const " ) ;
const bool lval ( argStart - > link ( ) - > strAt ( has_const ? 2 : 1 ) = = " & " ) ;
const bool rval ( argStart - > link ( ) - > strAt ( has_const ? 2 : 1 ) = = " && " ) ;
2014-07-24 16:34:13 +02:00
int count = 0 ;
std : : string path ;
unsigned int path_length = 0 ;
2018-05-01 07:32:19 +02:00
const Token * tok1 = ( * tok ) ;
if ( destructor )
tok1 = tok1 - > previous ( ) ;
2014-07-24 16:34:13 +02:00
2010-11-13 08:08:45 +01:00
// back up to head of path
2018-05-01 07:32:19 +02:00
while ( tok1 & & tok1 - > previous ( ) & & tok1 - > previous ( ) - > str ( ) = = " :: " & & tok1 - > tokAt ( - 2 ) & &
2021-01-19 18:52:47 +01:00
( ( tok1 - > tokAt ( - 2 ) - > isName ( ) & & ! tok1 - > tokAt ( - 2 ) - > isStandardType ( ) ) | |
2018-05-01 07:32:19 +02:00
( tok1 - > strAt ( - 2 ) = = " > " & & tok1 - > linkAt ( - 2 ) & & Token : : Match ( tok1 - > linkAt ( - 2 ) - > previous ( ) , " %name% " ) ) ) ) {
count + + ;
const Token * tok2 = tok1 - > tokAt ( - 2 ) ;
if ( tok2 - > str ( ) = = " > " )
tok2 = tok2 - > link ( ) - > previous ( ) ;
if ( tok2 ) {
do {
path = tok1 - > previous ( ) - > str ( ) + " " + path ;
tok1 = tok1 - > previous ( ) ;
path_length + + ;
} while ( tok1 ! = tok2 ) ;
} else
return ; // syntax error ?
2010-11-13 08:08:45 +01:00
}
2018-05-01 07:32:19 +02:00
// syntax error?
if ( ! tok1 )
return ;
2010-11-13 08:08:45 +01:00
2021-01-19 18:52:47 +01:00
// add global namespace if present
if ( tok1 - > strAt ( - 1 ) = = " :: " ) {
path_length + + ;
path . insert ( 0 , " :: " ) ;
}
2011-03-11 01:43:29 +01:00
std : : list < Scope > : : iterator it1 ;
2010-11-13 08:08:45 +01:00
// search for match
2011-10-13 20:53:06 +02:00
for ( it1 = scopeList . begin ( ) ; it1 ! = scopeList . end ( ) ; + + it1 ) {
2011-03-11 01:43:29 +01:00
Scope * scope1 = & ( * it1 ) ;
2010-11-13 08:08:45 +01:00
bool match = false ;
2014-04-10 16:11:11 +02:00
// check in namespace if using found
if ( * scope = = scope1 & & ! scope1 - > usingList . empty ( ) ) {
2022-06-08 16:58:57 +02:00
std : : vector < Scope : : UsingInfo > : : const_iterator it2 ;
2014-04-10 16:11:11 +02:00
for ( it2 = scope1 - > usingList . begin ( ) ; it2 ! = scope1 - > usingList . end ( ) ; + + it2 ) {
if ( it2 - > scope ) {
2018-05-01 07:32:19 +02:00
Function * func = findFunctionInScope ( tok1 , it2 - > scope , path , path_length ) ;
2014-04-10 16:11:11 +02:00
if ( func ) {
2015-01-08 05:45:31 +01:00
if ( ! func - > hasBody ( ) ) {
2019-10-18 18:05:48 +02:00
const Token * closeParen = ( * tok ) - > next ( ) - > link ( ) ;
if ( closeParen ) {
2020-09-03 11:21:12 +02:00
const Token * eq = mTokenizer - > isFunctionHead ( closeParen , " ; " ) ;
if ( eq & & Token : : simpleMatch ( eq - > tokAt ( - 2 ) , " = default ; " ) ) {
2019-10-18 18:05:48 +02:00
func - > isDefault ( true ) ;
return ;
}
}
2015-01-08 05:45:31 +01:00
func - > hasBody ( true ) ;
2014-04-10 16:11:11 +02:00
func - > token = * tok ;
func - > arg = argStart ;
addNewFunction ( scope , tok ) ;
if ( * scope ) {
( * scope ) - > functionOf = func - > nestedIn ;
2015-01-17 16:28:39 +01:00
( * scope ) - > function = func ;
2014-04-10 16:11:11 +02:00
( * scope ) - > function - > functionScope = * scope ;
}
return ;
}
}
}
}
}
2011-10-13 20:53:06 +02:00
if ( scope1 - > className = = tok1 - > str ( ) & & ( scope1 - > type ! = Scope : : eFunction ) ) {
2011-04-01 02:54:23 +02:00
// do the scopes match (same scope) or do their names match (multiple namespaces)
2013-08-21 16:32:10 +02:00
if ( ( * scope = = scope1 - > nestedIn ) | | ( * scope & &
2011-01-21 07:42:41 +01:00
( * scope ) - > className = = scope1 - > nestedIn - > className & &
! ( * scope ) - > className . empty ( ) & &
2011-10-13 20:53:06 +02:00
( * scope ) - > type = = scope1 - > nestedIn - > type ) ) {
2012-01-07 09:28:26 +01:00
// nested scopes => check that they match
{
const Scope * s1 = * scope ;
const Scope * s2 = scope1 - > nestedIn ;
while ( s1 & & s2 ) {
if ( s1 - > className ! = s2 - > className )
break ;
s1 = s1 - > nestedIn ;
s2 = s2 - > nestedIn ;
}
// Not matching scopes
if ( s1 | | s2 )
continue ;
}
2011-01-21 07:42:41 +01:00
Scope * scope2 = scope1 ;
2010-11-13 08:08:45 +01:00
2018-05-01 07:32:19 +02:00
while ( scope2 & & count > 1 ) {
2010-11-20 07:26:50 +01:00
count - - ;
2018-05-01 07:32:19 +02:00
if ( tok1 - > strAt ( 1 ) = = " < " )
tok1 = tok1 - > linkAt ( 1 ) - > tokAt ( 2 ) ;
else
tok1 = tok1 - > tokAt ( 2 ) ;
2018-04-24 22:43:47 +02:00
scope2 = scope2 - > findRecordInNestedList ( tok1 - > str ( ) ) ;
2010-11-20 07:26:50 +01:00
}
2018-05-01 07:32:19 +02:00
if ( count = = 1 & & scope2 ) {
2010-11-20 07:26:50 +01:00
match = true ;
2011-01-21 07:42:41 +01:00
scope1 = scope2 ;
2010-11-20 07:26:50 +01:00
}
2010-11-13 08:08:45 +01:00
}
}
2011-10-13 20:53:06 +02:00
if ( match ) {
2022-06-08 16:58:57 +02:00
auto range = scope1 - > functionMap . equal_range ( ( * tok ) - > str ( ) ) ;
for ( std : : multimap < std : : string , const Function * > : : const_iterator it = range . first ; it ! = range . second ; + + it ) {
2015-01-02 21:38:19 +01:00
Function * func = const_cast < Function * > ( it - > second ) ;
2015-01-08 05:45:31 +01:00
if ( ! func - > hasBody ( ) ) {
2021-01-18 19:01:04 +01:00
if ( func - > argsMatch ( scope1 , func - > argDef , ( * tok ) - > next ( ) , path , path_length ) ) {
Fix defaulted and deleted functions (#4540)
* Fix 9392, but for destructors: out-of-line defaulted destructors skipped everything after
Context:
```
struct S {
~S();
};
S::~S() = default;
void g() {
int j;
++j;
}
```
Everything after `S::~S() = default;` was skipped, so the uninitialized variables in g() weren't found.
Out-of-line destructors are useful e.g. when you have a forward declared unique_ptr in the .h,
and `= default` the destructor in the .cpp, so only the cpp needs to know the header for destructing
your unique_ptr (like in the pImpl-idiom)
* Fix unit test, by correctly fixing 10789
Previous commit broke this test, but also provided the tools for a cleaner fix
* Document current behaviour
* Rewrite control flow
* Fix deleted functions, which skipped everything after
`a::b f() = delete` triggered the final else in SymbolDatabase::addNewFunction,
which sets tok to nullptr, effectively skipping to the end of the stream.
* Remove troublesome nullptr, which skips every analysis afterwards
It was introduced in 0746c241 to fix a memory leak.
But setting tok to nullptr, effectively skipping to the end, seems not needed.
Previous commits fixes prevented some cases where you could enter the `else`.
This commit is more of a fall back.
* fixup! Fix deleted functions, which skipped everything after
`a::b f() = delete` triggered the final else in SymbolDatabase::addNewFunction,
which sets tok to nullptr, effectively skipping to the end of the stream.
* fixup! Fix deleted functions, which skipped everything after
`a::b f() = delete` triggered the final else in SymbolDatabase::addNewFunction,
which sets tok to nullptr, effectively skipping to the end of the stream.
* Make it heard when encountering unexpected syntax/tokens
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-10 20:17:33 +02:00
const Token * closeParen = ( * tok ) - > next ( ) - > link ( ) ;
if ( closeParen ) {
const Token * eq = mTokenizer - > isFunctionHead ( closeParen , " ; " ) ;
if ( eq & & Token : : simpleMatch ( eq - > tokAt ( - 2 ) , " = default ; " ) ) {
func - > isDefault ( true ) ;
return ;
}
if ( func - > type = = Function : : eDestructor & & destructor ) {
func - > hasBody ( true ) ;
} else if ( func - > type ! = Function : : eDestructor & & ! destructor ) {
// normal function?
2019-10-06 07:21:12 +02:00
const bool hasConstKeyword = closeParen - > next ( ) - > str ( ) = = " const " ;
2016-01-02 18:53:51 +01:00
if ( ( func - > isConst ( ) = = hasConstKeyword ) & &
( func - > hasLvalRefQualifier ( ) = = lval ) & &
( func - > hasRvalRefQualifier ( ) = = rval ) ) {
2015-01-08 05:45:31 +01:00
func - > hasBody ( true ) ;
2010-11-13 08:08:45 +01:00
}
}
}
2015-01-08 05:45:31 +01:00
if ( func - > hasBody ( ) ) {
2012-05-22 21:58:46 +02:00
func - > token = * tok ;
func - > arg = argStart ;
addNewFunction ( scope , tok ) ;
if ( * scope ) {
( * scope ) - > functionOf = scope1 ;
2015-01-17 16:28:39 +01:00
( * scope ) - > function = func ;
2012-05-22 21:58:46 +02:00
( * scope ) - > function - > functionScope = * scope ;
}
return ;
2010-12-16 19:04:47 +01:00
}
2010-11-13 08:08:45 +01:00
}
}
}
}
}
2012-04-27 21:51:13 +02:00
// class function of unknown class
addNewFunction ( scope , tok ) ;
2010-11-13 08:08:45 +01:00
}
2011-01-21 07:42:41 +01:00
void SymbolDatabase : : addNewFunction ( Scope * * scope , const Token * * tok )
2010-11-13 08:08:45 +01:00
{
const Token * tok1 = * tok ;
2018-04-11 09:44:35 +02:00
scopeList . emplace_back ( this , tok1 , * scope ) ;
2015-09-04 16:00:44 +02:00
Scope * newScope = & scopeList . back ( ) ;
2010-11-13 08:08:45 +01:00
2015-04-06 19:47:21 +02:00
// find start of function '{'
bool foundInitList = false ;
while ( tok1 & & tok1 - > str ( ) ! = " { " & & tok1 - > str ( ) ! = " ; " ) {
2022-01-26 06:28:13 +01:00
if ( tok1 - > link ( ) & & Token : : Match ( tok1 , " (|[|< " ) ) {
2012-07-10 15:15:11 +02:00
tok1 = tok1 - > link ( ) ;
2022-01-26 06:28:13 +01:00
} else if ( foundInitList & & Token : : Match ( tok1 , " %name%|> { " ) & & Token : : Match ( tok1 - > linkAt ( 1 ) , " } ,| { " )) {
2015-04-06 19:47:21 +02:00
tok1 = tok1 - > linkAt ( 1 ) ;
} else {
if ( tok1 - > str ( ) = = " : " )
foundInitList = true ;
tok1 = tok1 - > next ( ) ;
}
2012-07-10 15:15:11 +02:00
}
2010-11-13 08:08:45 +01:00
2015-04-06 19:47:21 +02:00
if ( tok1 & & tok1 - > str ( ) = = " { " ) {
2021-08-10 07:00:11 +02:00
newScope - > setBodyStartEnd ( tok1 ) ;
2010-11-13 08:08:45 +01:00
2010-12-16 19:04:47 +01:00
// syntax error?
2018-04-27 22:36:30 +02:00
if ( ! newScope - > bodyEnd ) {
Fix defaulted and deleted functions (#4540)
* Fix 9392, but for destructors: out-of-line defaulted destructors skipped everything after
Context:
```
struct S {
~S();
};
S::~S() = default;
void g() {
int j;
++j;
}
```
Everything after `S::~S() = default;` was skipped, so the uninitialized variables in g() weren't found.
Out-of-line destructors are useful e.g. when you have a forward declared unique_ptr in the .h,
and `= default` the destructor in the .cpp, so only the cpp needs to know the header for destructing
your unique_ptr (like in the pImpl-idiom)
* Fix unit test, by correctly fixing 10789
Previous commit broke this test, but also provided the tools for a cleaner fix
* Document current behaviour
* Rewrite control flow
* Fix deleted functions, which skipped everything after
`a::b f() = delete` triggered the final else in SymbolDatabase::addNewFunction,
which sets tok to nullptr, effectively skipping to the end of the stream.
* Remove troublesome nullptr, which skips every analysis afterwards
It was introduced in 0746c241 to fix a memory leak.
But setting tok to nullptr, effectively skipping to the end, seems not needed.
Previous commits fixes prevented some cases where you could enter the `else`.
This commit is more of a fall back.
* fixup! Fix deleted functions, which skipped everything after
`a::b f() = delete` triggered the final else in SymbolDatabase::addNewFunction,
which sets tok to nullptr, effectively skipping to the end of the stream.
* fixup! Fix deleted functions, which skipped everything after
`a::b f() = delete` triggered the final else in SymbolDatabase::addNewFunction,
which sets tok to nullptr, effectively skipping to the end of the stream.
* Make it heard when encountering unexpected syntax/tokens
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-10 20:17:33 +02:00
mTokenizer - > unmatchedToken ( tok1 ) ;
} else {
( * scope ) - > nestedList . push_back ( newScope ) ;
* scope = newScope ;
2010-12-16 19:04:47 +01:00
}
Fix defaulted and deleted functions (#4540)
* Fix 9392, but for destructors: out-of-line defaulted destructors skipped everything after
Context:
```
struct S {
~S();
};
S::~S() = default;
void g() {
int j;
++j;
}
```
Everything after `S::~S() = default;` was skipped, so the uninitialized variables in g() weren't found.
Out-of-line destructors are useful e.g. when you have a forward declared unique_ptr in the .h,
and `= default` the destructor in the .cpp, so only the cpp needs to know the header for destructing
your unique_ptr (like in the pImpl-idiom)
* Fix unit test, by correctly fixing 10789
Previous commit broke this test, but also provided the tools for a cleaner fix
* Document current behaviour
* Rewrite control flow
* Fix deleted functions, which skipped everything after
`a::b f() = delete` triggered the final else in SymbolDatabase::addNewFunction,
which sets tok to nullptr, effectively skipping to the end of the stream.
* Remove troublesome nullptr, which skips every analysis afterwards
It was introduced in 0746c241 to fix a memory leak.
But setting tok to nullptr, effectively skipping to the end, seems not needed.
Previous commits fixes prevented some cases where you could enter the `else`.
This commit is more of a fall back.
* fixup! Fix deleted functions, which skipped everything after
`a::b f() = delete` triggered the final else in SymbolDatabase::addNewFunction,
which sets tok to nullptr, effectively skipping to the end of the stream.
* fixup! Fix deleted functions, which skipped everything after
`a::b f() = delete` triggered the final else in SymbolDatabase::addNewFunction,
which sets tok to nullptr, effectively skipping to the end of the stream.
* Make it heard when encountering unexpected syntax/tokens
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-10 20:17:33 +02:00
} else if ( tok1 & & Token : : Match ( tok1 - > tokAt ( - 2 ) , " = default|delete ; " )) {
2011-03-11 01:43:29 +01:00
scopeList . pop_back ( ) ;
Fix defaulted and deleted functions (#4540)
* Fix 9392, but for destructors: out-of-line defaulted destructors skipped everything after
Context:
```
struct S {
~S();
};
S::~S() = default;
void g() {
int j;
++j;
}
```
Everything after `S::~S() = default;` was skipped, so the uninitialized variables in g() weren't found.
Out-of-line destructors are useful e.g. when you have a forward declared unique_ptr in the .h,
and `= default` the destructor in the .cpp, so only the cpp needs to know the header for destructing
your unique_ptr (like in the pImpl-idiom)
* Fix unit test, by correctly fixing 10789
Previous commit broke this test, but also provided the tools for a cleaner fix
* Document current behaviour
* Rewrite control flow
* Fix deleted functions, which skipped everything after
`a::b f() = delete` triggered the final else in SymbolDatabase::addNewFunction,
which sets tok to nullptr, effectively skipping to the end of the stream.
* Remove troublesome nullptr, which skips every analysis afterwards
It was introduced in 0746c241 to fix a memory leak.
But setting tok to nullptr, effectively skipping to the end, seems not needed.
Previous commits fixes prevented some cases where you could enter the `else`.
This commit is more of a fall back.
* fixup! Fix deleted functions, which skipped everything after
`a::b f() = delete` triggered the final else in SymbolDatabase::addNewFunction,
which sets tok to nullptr, effectively skipping to the end of the stream.
* fixup! Fix deleted functions, which skipped everything after
`a::b f() = delete` triggered the final else in SymbolDatabase::addNewFunction,
which sets tok to nullptr, effectively skipping to the end of the stream.
* Make it heard when encountering unexpected syntax/tokens
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-10 20:17:33 +02:00
} else {
throw InternalError ( * tok , " Analysis failed (function not recognized) . If the code is valid then please report this failure . " ) ;
2011-01-22 08:36:47 +01:00
}
Fix defaulted and deleted functions (#4540)
* Fix 9392, but for destructors: out-of-line defaulted destructors skipped everything after
Context:
```
struct S {
~S();
};
S::~S() = default;
void g() {
int j;
++j;
}
```
Everything after `S::~S() = default;` was skipped, so the uninitialized variables in g() weren't found.
Out-of-line destructors are useful e.g. when you have a forward declared unique_ptr in the .h,
and `= default` the destructor in the .cpp, so only the cpp needs to know the header for destructing
your unique_ptr (like in the pImpl-idiom)
* Fix unit test, by correctly fixing 10789
Previous commit broke this test, but also provided the tools for a cleaner fix
* Document current behaviour
* Rewrite control flow
* Fix deleted functions, which skipped everything after
`a::b f() = delete` triggered the final else in SymbolDatabase::addNewFunction,
which sets tok to nullptr, effectively skipping to the end of the stream.
* Remove troublesome nullptr, which skips every analysis afterwards
It was introduced in 0746c241 to fix a memory leak.
But setting tok to nullptr, effectively skipping to the end, seems not needed.
Previous commits fixes prevented some cases where you could enter the `else`.
This commit is more of a fall back.
* fixup! Fix deleted functions, which skipped everything after
`a::b f() = delete` triggered the final else in SymbolDatabase::addNewFunction,
which sets tok to nullptr, effectively skipping to the end of the stream.
* fixup! Fix deleted functions, which skipped everything after
`a::b f() = delete` triggered the final else in SymbolDatabase::addNewFunction,
which sets tok to nullptr, effectively skipping to the end of the stream.
* Make it heard when encountering unexpected syntax/tokens
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-10 20:17:33 +02:00
* tok = tok1 ;
2010-11-13 08:08:45 +01:00
}
2020-10-02 20:22:09 +02:00
bool Type : : isClassType ( ) const
{
return classScope & & classScope - > type = = Scope : : ScopeType : : eClass ;
}
bool Type : : isEnumType ( ) const
{
2020-10-30 18:32:35 +01:00
//We explicitly check for "enum" because a forward declared enum doesn't get its own scope
return ( classDef & & classDef - > str ( ) = = " enum " ) | |
( classScope & & classScope - > type = = Scope : : ScopeType : : eEnum ) ;
2020-10-02 20:22:09 +02:00
}
bool Type : : isStructType ( ) const
{
return classScope & & classScope - > type = = Scope : : ScopeType : : eStruct ;
}
bool Type : : isUnionType ( ) const
{
return classScope & & classScope - > type = = Scope : : ScopeType : : eUnion ;
}
2013-03-05 15:28:40 +01:00
const Token * Type : : initBaseInfo ( const Token * tok , const Token * tok1 )
2010-11-13 08:08:45 +01:00
{
// goto initial '{'
2012-11-30 06:03:58 +01:00
const Token * tok2 = tok1 ;
2011-10-13 20:53:06 +02:00
while ( tok2 & & tok2 - > str ( ) ! = " { " ) {
2010-11-13 08:08:45 +01:00
// skip unsupported templates
if ( tok2 - > str ( ) = = " < " )
2013-04-15 22:48:28 +02:00
tok2 = tok2 - > link ( ) ;
2010-11-13 08:08:45 +01:00
// check for base classes
2012-04-27 21:51:13 +02:00
else if ( Token : : Match ( tok2 , " :|, " ) ) {
2010-11-13 08:08:45 +01:00
tok2 = tok2 - > next ( ) ;
2011-02-19 20:38:00 +01:00
// check for invalid code
2011-02-21 20:25:35 +01:00
if ( ! tok2 | | ! tok2 - > next ( ) )
2014-02-16 10:32:10 +01:00
return nullptr ;
2011-02-19 20:38:00 +01:00
2014-09-19 09:29:31 +02:00
Type : : BaseInfo base ;
2011-10-13 20:53:06 +02:00
if ( tok2 - > str ( ) = = " virtual " ) {
2011-03-22 01:03:41 +01:00
base . isVirtual = true ;
tok2 = tok2 - > next ( ) ;
}
2011-10-13 20:53:06 +02:00
if ( tok2 - > str ( ) = = " public " ) {
2019-07-23 14:29:02 +02:00
base . access = AccessControl : : Public ;
2010-11-13 08:08:45 +01:00
tok2 = tok2 - > next ( ) ;
2011-10-13 20:53:06 +02:00
} else if ( tok2 - > str ( ) = = " protected " ) {
2019-07-23 14:29:02 +02:00
base . access = AccessControl : : Protected ;
2010-11-13 08:08:45 +01:00
tok2 = tok2 - > next ( ) ;
2011-10-13 20:53:06 +02:00
} else if ( tok2 - > str ( ) = = " private " ) {
2019-07-23 14:29:02 +02:00
base . access = AccessControl : : Private ;
2010-11-13 08:08:45 +01:00
tok2 = tok2 - > next ( ) ;
2011-10-13 20:53:06 +02:00
} else {
2010-11-13 08:08:45 +01:00
if ( tok - > str ( ) = = " class " )
2019-07-23 14:29:02 +02:00
base . access = AccessControl : : Private ;
2010-11-13 08:08:45 +01:00
else if ( tok - > str ( ) = = " struct " )
2019-07-23 14:29:02 +02:00
base . access = AccessControl : : Public ;
2010-11-13 08:08:45 +01:00
}
2015-06-02 18:28:43 +02:00
if ( ! tok2 )
return nullptr ;
2011-10-13 20:53:06 +02:00
if ( tok2 - > str ( ) = = " virtual " ) {
2011-03-22 01:03:41 +01:00
base . isVirtual = true ;
tok2 = tok2 - > next ( ) ;
2011-06-30 01:43:39 +02:00
}
2015-06-02 20:15:21 +02:00
if ( ! tok2 )
return nullptr ;
2015-09-04 15:06:20 +02:00
base . nameTok = tok2 ;
2011-06-30 01:43:39 +02:00
// handle global namespace
2011-10-13 20:53:06 +02:00
if ( tok2 - > str ( ) = = " :: " ) {
2011-06-30 01:43:39 +02:00
tok2 = tok2 - > next ( ) ;
2011-03-22 01:03:41 +01:00
}
2010-11-13 08:08:45 +01:00
// handle derived base classes
2015-01-31 10:50:39 +01:00
while ( Token : : Match ( tok2 , " %name% :: " ) ) {
2010-11-13 08:08:45 +01:00
tok2 = tok2 - > tokAt ( 2 ) ;
}
2015-06-02 20:15:21 +02:00
if ( ! tok2 )
return nullptr ;
2010-11-13 08:08:45 +01:00
2013-03-05 15:28:40 +01:00
base . name = tok2 - > str ( ) ;
2010-11-13 08:08:45 +01:00
2015-01-09 22:03:43 +01:00
tok2 = tok2 - > next ( ) ;
2011-02-15 01:50:13 +01:00
// add unhandled templates
2015-01-09 22:03:43 +01:00
if ( tok2 & & tok2 - > link ( ) & & tok2 - > str ( ) = = " < " ) {
for ( const Token * const end = tok2 - > link ( ) - > next ( ) ; tok2 ! = end ; tok2 = tok2 - > next ( ) ) {
base . name + = tok2 - > str ( ) ;
2010-11-30 19:52:42 +01:00
}
2010-11-25 07:43:39 +01:00
}
2021-02-17 18:12:49 +01:00
const Type * baseType = classScope - > check - > findType ( base . nameTok , enclosingScope ) ;
if ( baseType & & ! baseType - > findDependency ( this ) )
base . type = baseType ;
2021-01-18 19:01:04 +01:00
2010-11-13 08:08:45 +01:00
// save pattern for base class name
2022-09-08 09:21:35 +02:00
derivedFrom . push_back ( std : : move ( base ) ) ;
2015-01-09 22:03:43 +01:00
} else
2013-06-16 21:46:01 +02:00
tok2 = tok2 - > next ( ) ;
2010-11-13 08:08:45 +01:00
}
return tok2 ;
}
2011-01-15 07:59:37 +01:00
2016-04-22 06:02:54 +02:00
const std : : string & Type : : name ( ) const
{
const Token * next = classDef - > next ( ) ;
2016-07-25 18:22:15 +02:00
if ( classScope & & classScope - > enumClass & & isEnumType ( ) )
2016-04-22 06:02:54 +02:00
return next - > strAt ( 1 ) ;
2018-05-04 07:56:20 +02:00
else if ( next - > str ( ) = = " class " )
return next - > strAt ( 1 ) ;
2016-04-22 06:02:54 +02:00
else if ( next - > isName ( ) )
return next - > str ( ) ;
return emptyString ;
}
2020-12-31 19:24:16 +01:00
void SymbolDatabase : : debugMessage ( const Token * tok , const std : : string & type , const std : : string & msg ) const
2011-03-03 03:08:27 +01:00
{
2018-06-16 16:10:28 +02:00
if ( tok & & mSettings - > debugwarnings ) {
2012-05-06 13:01:56 +02:00
const std : : list < const Token * > locationList ( 1 , tok ) ;
2020-05-23 07:16:49 +02:00
const ErrorMessage errmsg ( locationList , & mTokenizer - > list ,
Severity : : debug ,
2020-12-31 19:24:29 +01:00
type ,
2020-05-23 07:16:49 +02:00
msg ,
2021-02-24 22:00:06 +01:00
Certainty : : normal ) ;
2018-06-16 16:10:28 +02:00
if ( mErrorLogger )
mErrorLogger - > reportErr ( errmsg ) ;
2011-03-03 03:08:27 +01:00
}
}
2013-03-14 17:00:22 +01:00
const Function * Type : : getFunction ( const std : : string & funcName ) const
{
if ( classScope ) {
2018-04-04 21:51:31 +02:00
const std : : multimap < std : : string , const Function * > : : const_iterator it = classScope - > functionMap . find ( funcName ) ;
2015-01-02 21:38:19 +01:00
if ( it ! = classScope - > functionMap . end ( ) )
return it - > second ;
2013-03-14 17:00:22 +01:00
}
2019-09-19 20:29:33 +02:00
for ( const Type : : BaseInfo & i : derivedFrom ) {
if ( i . type ) {
const Function * const func = i . type - > getFunction ( funcName ) ;
2013-03-14 17:00:22 +01:00
if ( func )
return func ;
}
}
2017-08-09 20:00:26 +02:00
return nullptr ;
2013-03-14 17:00:22 +01:00
}
2015-09-04 15:12:40 +02:00
bool Type : : hasCircularDependencies ( std : : set < BaseInfo > * ancestors ) const
2014-03-29 12:21:35 +01:00
{
2015-09-04 15:12:40 +02:00
std : : set < BaseInfo > knownAncestors ;
if ( ! ancestors ) {
ancestors = & knownAncestors ;
2014-03-29 12:21:35 +01:00
}
for ( std : : vector < BaseInfo > : : const_iterator parent = derivedFrom . begin ( ) ; parent ! = derivedFrom . end ( ) ; + + parent ) {
if ( ! parent - > type )
continue ;
else if ( this = = parent - > type )
return true ;
2015-09-04 15:12:40 +02:00
else if ( ancestors - > find ( * parent ) ! = ancestors - > end ( ) )
2014-03-29 12:21:35 +01:00
return true ;
else {
2015-09-04 15:12:40 +02:00
ancestors - > insert ( * parent ) ;
if ( parent - > type - > hasCircularDependencies ( ancestors ) )
2014-03-29 12:21:35 +01:00
return true ;
}
}
return false ;
}
2015-09-04 15:12:40 +02:00
bool Type : : findDependency ( const Type * ancestor ) const
2015-07-01 07:50:13 +02:00
{
2022-10-16 13:46:26 +02:00
return this = = ancestor | | std : : any_of ( derivedFrom . begin ( ) , derivedFrom . end ( ) , [ & ] ( const BaseInfo & d ) {
return d . type & & ( d . type = = this | | d . type - > findDependency ( ancestor ) ) ;
} ) ;
2015-07-01 00:04:01 +02:00
}
2016-08-19 19:06:15 +02:00
bool Type : : isDerivedFrom ( const std : : string & ancestor ) const
{
for ( std : : vector < BaseInfo > : : const_iterator parent = derivedFrom . begin ( ) ; parent ! = derivedFrom . end ( ) ; + + parent ) {
if ( parent - > name = = ancestor )
return true ;
if ( parent - > type & & parent - > type - > isDerivedFrom ( ancestor ) )
return true ;
}
return false ;
}
2021-11-08 20:31:16 +01:00
bool Variable : : arrayDimensions ( const Settings * settings , bool * isContainer )
2011-06-23 04:41:11 +02:00
{
2021-11-08 20:31:16 +01:00
* isContainer = false ;
2019-03-15 19:00:42 +01:00
const Library : : Container * container = settings - > library . detectContainer ( mTypeStartToken ) ;
2015-01-30 21:56:27 +01:00
if ( container & & container - > arrayLike_indexOp & & container - > size_templateArgNo > 0 ) {
2018-06-16 16:03:36 +02:00
const Token * tok = Token : : findsimplematch ( mTypeStartToken , " < " ) ;
2015-01-30 21:56:27 +01:00
if ( tok ) {
2021-11-08 20:31:16 +01:00
* isContainer = true ;
2015-08-26 13:48:19 +02:00
Dimension dimension_ ;
2015-01-30 21:56:27 +01:00
tok = tok - > next ( ) ;
for ( int i = 0 ; i < container - > size_templateArgNo & & tok ; i + + ) {
tok = tok - > nextTemplateArgument ( ) ;
}
2020-02-19 07:36:02 +01:00
if ( Token : : Match ( tok , " %num% [,>] " ) ) {
2019-03-15 19:00:42 +01:00
dimension_ . tok = tok ;
2020-02-19 07:36:02 +01:00
dimension_ . known = true ;
dimension_ . num = MathLib : : toLongNumber ( tok - > str ( ) ) ;
} else if ( tok ) {
dimension_ . tok = tok ;
dimension_ . known = false ;
2015-01-30 21:56:27 +01:00
}
2018-06-16 20:23:58 +02:00
mDimensions . push_back ( dimension_ ) ;
2015-01-30 21:56:27 +01:00
return true ;
}
}
2011-06-23 04:41:11 +02:00
2018-06-16 15:57:16 +02:00
const Token * dim = mNameToken ;
2015-01-30 21:56:27 +01:00
if ( ! dim ) {
// Argument without name
2018-06-16 16:03:36 +02:00
dim = mTypeEndToken ;
2015-01-30 21:56:27 +01:00
// back up to start of array dimensions
while ( dim & & dim - > str ( ) = = " ] " )
dim = dim - > link ( ) - > previous ( ) ;
}
if ( dim )
dim = dim - > next ( ) ;
2015-01-31 13:12:06 +01:00
if ( dim & & dim - > str ( ) = = " ) " )
dim = dim - > next ( ) ;
2011-06-23 04:41:11 +02:00
2015-01-30 22:04:26 +01:00
bool arr = false ;
2011-10-13 20:53:06 +02:00
while ( dim & & dim - > next ( ) & & dim - > str ( ) = = " [ " ) {
2015-01-30 22:04:26 +01:00
Dimension dimension_ ;
2019-03-15 19:00:42 +01:00
dimension_ . known = false ;
2011-08-28 19:32:42 +02:00
// check for empty array dimension []
2011-10-13 20:53:06 +02:00
if ( dim - > next ( ) - > str ( ) ! = " ] " ) {
2019-03-15 19:00:42 +01:00
dimension_ . tok = dim - > astOperand2 ( ) ;
2019-06-16 10:09:38 +02:00
ValueFlow : : valueFlowConstantFoldAST ( const_cast < Token * > ( dimension_ . tok ) , settings ) ;
2019-03-15 19:00:42 +01:00
if ( dimension_ . tok & & dimension_ . tok - > hasKnownIntValue ( ) ) {
dimension_ . num = dimension_ . tok - > getKnownIntValue ( ) ;
2016-04-22 06:02:54 +02:00
dimension_ . known = true ;
}
2011-08-28 19:32:42 +02:00
}
2018-06-16 20:23:58 +02:00
mDimensions . push_back ( dimension_ ) ;
2011-06-23 04:41:11 +02:00
dim = dim - > link ( ) - > next ( ) ;
2015-01-30 22:04:26 +01:00
arr = true ;
2011-06-23 04:41:11 +02:00
}
2015-01-30 22:04:26 +01:00
return arr ;
2011-06-23 04:41:11 +02:00
}
2012-01-05 18:22:54 +01:00
static std : : ostream & operator < < ( std : : ostream & s , Scope : : ScopeType type )
{
s < < ( type = = Scope : : eGlobal ? " Global " :
type = = Scope : : eClass ? " Class " :
type = = Scope : : eStruct ? " Struct " :
type = = Scope : : eUnion ? " Union " :
type = = Scope : : eNamespace ? " Namespace " :
type = = Scope : : eFunction ? " Function " :
type = = Scope : : eIf ? " If " :
type = = Scope : : eElse ? " Else " :
type = = Scope : : eFor ? " For " :
type = = Scope : : eWhile ? " While " :
type = = Scope : : eDo ? " Do " :
type = = Scope : : eSwitch ? " Switch " :
2012-01-26 04:05:29 +01:00
type = = Scope : : eTry ? " Try " :
type = = Scope : : eCatch ? " Catch " :
2012-01-05 18:22:54 +01:00
type = = Scope : : eUnconditional ? " Unconditional " :
2014-08-31 10:21:10 +02:00
type = = Scope : : eLambda ? " Lambda " :
2016-04-22 06:02:54 +02:00
type = = Scope : : eEnum ? " Enum " :
2012-01-05 18:22:54 +01:00
" Unknown " ) ;
return s ;
}
2017-04-29 07:18:16 +02:00
static std : : string accessControlToString ( const AccessControl & access )
{
switch ( access ) {
2019-07-23 14:29:02 +02:00
case AccessControl : : Public :
2017-04-29 07:18:16 +02:00
return " Public " ;
2019-07-23 14:29:02 +02:00
case AccessControl : : Protected :
2017-04-29 07:18:16 +02:00
return " Protected " ;
2019-07-23 14:29:02 +02:00
case AccessControl : : Private :
2017-04-29 07:18:16 +02:00
return " Private " ;
2019-07-23 14:29:02 +02:00
case AccessControl : : Global :
2017-04-29 07:18:16 +02:00
return " Global " ;
2019-07-23 14:29:02 +02:00
case AccessControl : : Namespace :
2017-04-29 07:18:16 +02:00
return " Namespace " ;
2019-07-23 14:29:02 +02:00
case AccessControl : : Argument :
2017-04-29 07:18:16 +02:00
return " Argument " ;
2019-07-23 14:29:02 +02:00
case AccessControl : : Local :
2017-04-29 07:18:16 +02:00
return " Local " ;
2019-07-23 14:29:02 +02:00
case AccessControl : : Throw :
2017-04-29 07:18:16 +02:00
return " Throw " ;
}
return " Unknown " ;
}
2015-01-09 21:40:50 +01:00
static std : : string tokenToString ( const Token * tok , const Tokenizer * tokenizer )
2015-01-09 21:34:57 +01:00
{
std : : ostringstream oss ;
if ( tok ) {
oss < < tok - > str ( ) < < " " ;
2015-01-09 21:40:50 +01:00
oss < < tokenizer - > list . fileLine ( tok ) < < " " ;
2015-01-09 21:34:57 +01:00
}
oss < < tok ;
return oss . str ( ) ;
}
2015-01-09 21:40:50 +01:00
static std : : string scopeToString ( const Scope * scope , const Tokenizer * tokenizer )
2015-01-09 21:34:57 +01:00
{
std : : ostringstream oss ;
if ( scope ) {
oss < < scope - > type < < " " ;
2020-12-18 07:46:01 +01:00
if ( ! scope - > className . empty ( ) )
oss < < scope - > className < < " " ;
2015-01-09 21:34:57 +01:00
if ( scope - > classDef )
2015-01-09 21:40:50 +01:00
oss < < tokenizer - > list . fileLine ( scope - > classDef ) < < " " ;
2015-01-09 21:34:57 +01:00
}
oss < < scope ;
return oss . str ( ) ;
}
2017-04-08 01:57:10 +02:00
static std : : string tokenType ( const Token * tok )
{
std : : ostringstream oss ;
if ( tok ) {
if ( tok - > isUnsigned ( ) )
oss < < " unsigned " ;
else if ( tok - > isSigned ( ) )
oss < < " signed " ;
if ( tok - > isComplex ( ) )
oss < < " _Complex " ;
if ( tok - > isLong ( ) )
oss < < " long " ;
oss < < tok - > str ( ) ;
}
return oss . str ( ) ;
}
2012-01-05 18:22:54 +01:00
void SymbolDatabase : : printVariable ( const Variable * var , const char * indent ) const
{
2018-06-16 16:10:28 +02:00
std : : cout < < indent < < " mNameToken: " < < tokenToString ( var - > nameToken ( ) , mTokenizer ) < < std : : endl ;
2012-01-05 18:24:27 +01:00
if ( var - > nameToken ( ) ) {
2013-07-20 12:31:04 +02:00
std : : cout < < indent < < " declarationId: " < < var - > declarationId ( ) < < std : : endl ;
2015-01-09 21:34:57 +01:00
}
2018-06-16 16:10:28 +02:00
std : : cout < < indent < < " mTypeStartToken: " < < tokenToString ( var - > typeStartToken ( ) , mTokenizer ) < < std : : endl ;
std : : cout < < indent < < " mTypeEndToken: " < < tokenToString ( var - > typeEndToken ( ) , mTokenizer ) < < std : : endl ;
2017-04-08 01:57:10 +02:00
2020-01-05 19:18:32 +01:00
if ( var - > typeStartToken ( ) ) {
const Token * autoTok = nullptr ;
std : : cout < < indent < < " " ;
for ( const Token * tok = var - > typeStartToken ( ) ; tok ! = var - > typeEndToken ( ) - > next ( ) ; tok = tok - > next ( ) ) {
std : : cout < < " " < < tokenType ( tok ) ;
if ( tok - > str ( ) = = " auto " )
autoTok = tok ;
}
std : : cout < < std : : endl ;
if ( autoTok ) {
const ValueType * valueType = autoTok - > valueType ( ) ;
std : : cout < < indent < < " auto valueType: " < < valueType < < std : : endl ;
if ( var - > typeStartToken ( ) - > valueType ( ) ) {
std : : cout < < indent < < " " < < valueType - > str ( ) < < std : : endl ;
}
}
} else if ( var - > valueType ( ) ) {
std : : cout < < indent < < " " < < var - > valueType ( ) - > str ( ) < < std : : endl ;
2017-04-08 01:57:10 +02:00
}
2018-06-16 16:11:40 +02:00
std : : cout < < indent < < " mIndex: " < < var - > index ( ) < < std : : endl ;
2018-11-04 13:29:29 +01:00
std : : cout < < indent < < " mAccess: " < < accessControlToString ( var - > accessControl ( ) ) < < std : : endl ;
2018-06-16 16:14:34 +02:00
std : : cout < < indent < < " mFlags: " < < std : : endl ;
2015-01-09 21:34:57 +01:00
std : : cout < < indent < < " isMutable: " < < var - > isMutable ( ) < < std : : endl ;
std : : cout < < indent < < " isStatic: " < < var - > isStatic ( ) < < std : : endl ;
std : : cout < < indent < < " isExtern: " < < var - > isExtern ( ) < < std : : endl ;
std : : cout < < indent < < " isLocal: " < < var - > isLocal ( ) < < std : : endl ;
std : : cout < < indent < < " isConst: " < < var - > isConst ( ) < < std : : endl ;
std : : cout < < indent < < " isClass: " < < var - > isClass ( ) < < std : : endl ;
std : : cout < < indent < < " isArray: " < < var - > isArray ( ) < < std : : endl ;
std : : cout < < indent < < " isPointer: " < < var - > isPointer ( ) < < std : : endl ;
std : : cout < < indent < < " isReference: " < < var - > isReference ( ) < < std : : endl ;
std : : cout < < indent < < " isRValueRef: " < < var - > isRValueReference ( ) < < std : : endl ;
std : : cout < < indent < < " hasDefault: " < < var - > hasDefault ( ) < < std : : endl ;
std : : cout < < indent < < " isStlType: " < < var - > isStlType ( ) < < std : : endl ;
2018-06-16 20:25:54 +02:00
std : : cout < < indent < < " mType: " ;
2012-01-05 18:24:27 +01:00
if ( var - > type ( ) ) {
2016-08-04 09:06:32 +02:00
std : : cout < < var - > type ( ) - > type ( ) < < " " < < var - > type ( ) - > name ( ) ;
2018-06-16 16:10:28 +02:00
std : : cout < < " " < < mTokenizer - > list . fileLine ( var - > type ( ) - > classDef ) ;
2015-02-04 06:08:41 +01:00
std : : cout < < " " < < var - > type ( ) < < std : : endl ;
2012-01-05 18:24:27 +01:00
} else
2012-01-05 18:22:54 +01:00
std : : cout < < " none " < < std : : endl ;
2017-04-08 01:57:10 +02:00
if ( var - > nameToken ( ) ) {
const ValueType * valueType = var - > nameToken ( ) - > valueType ( ) ;
std : : cout < < indent < < " valueType: " < < valueType < < std : : endl ;
if ( valueType ) {
std : : cout < < indent < < " " < < valueType - > str ( ) < < std : : endl ;
}
}
2018-06-16 20:29:17 +02:00
std : : cout < < indent < < " mScope: " < < scopeToString ( var - > scope ( ) , mTokenizer ) < < std : : endl ;
2012-01-05 18:22:54 +01:00
2018-06-16 20:23:58 +02:00
std : : cout < < indent < < " mDimensions: " ;
2012-07-08 23:39:46 +02:00
for ( std : : size_t i = 0 ; i < var - > dimensions ( ) . size ( ) ; i + + ) {
2012-01-05 18:24:27 +01:00
std : : cout < < " " < < var - > dimension ( i ) ;
2012-09-10 16:14:24 +02:00
if ( ! var - > dimensions ( ) [ i ] . known )
std : : cout < < " ? " ;
2012-01-05 18:22:54 +01:00
}
std : : cout < < std : : endl ;
}
void SymbolDatabase : : printOut ( const char * title ) const
{
2015-01-09 21:34:57 +01:00
std : : cout < < std : : setiosflags ( std : : ios : : boolalpha ) ;
2012-01-05 18:22:54 +01:00
if ( title )
std : : cout < < " \n ### " < < title < < " ### \n " ;
2022-06-08 16:58:57 +02:00
for ( std : : list < Scope > : : const_iterator scope = scopeList . cbegin ( ) ; scope ! = scopeList . cend ( ) ; + + scope ) {
2015-01-09 21:34:57 +01:00
std : : cout < < " Scope: " < < & * scope < < " " < < scope - > type < < std : : endl ;
2012-01-05 18:22:54 +01:00
std : : cout < < " className: " < < scope - > className < < std : : endl ;
2018-06-16 16:10:28 +02:00
std : : cout < < " classDef: " < < tokenToString ( scope - > classDef , mTokenizer ) < < std : : endl ;
std : : cout < < " bodyStart: " < < tokenToString ( scope - > bodyStart , mTokenizer ) < < std : : endl ;
std : : cout < < " bodyEnd: " < < tokenToString ( scope - > bodyEnd , mTokenizer ) < < std : : endl ;
2012-01-05 18:22:54 +01:00
// find the function body if not implemented inline
2022-06-08 16:58:57 +02:00
for ( auto func = scope - > functionList . cbegin ( ) ; func ! = scope - > functionList . cend ( ) ; + + func ) {
2012-01-05 18:22:54 +01:00
std : : cout < < " Function: " < < & * func < < std : : endl ;
2018-06-16 16:10:28 +02:00
std : : cout < < " name: " < < tokenToString ( func - > tokenDef , mTokenizer ) < < std : : endl ;
2012-01-05 18:22:54 +01:00
std : : cout < < " type: " < < ( func - > type = = Function : : eConstructor ? " Constructor " :
func - > type = = Function : : eCopyConstructor ? " CopyConstructor " :
2013-04-04 19:53:55 +02:00
func - > type = = Function : : eMoveConstructor ? " MoveConstructor " :
2012-01-05 18:22:54 +01:00
func - > type = = Function : : eOperatorEqual ? " OperatorEqual " :
func - > type = = Function : : eDestructor ? " Destructor " :
func - > type = = Function : : eFunction ? " Function " :
2019-07-11 08:25:25 +02:00
func - > type = = Function : : eLambda ? " Lambda " :
2015-01-09 21:34:57 +01:00
" Unknown " ) < < std : : endl ;
2018-11-04 13:29:29 +01:00
std : : cout < < " access: " < < accessControlToString ( func - > access ) < < std : : endl ;
2015-01-09 21:34:57 +01:00
std : : cout < < " hasBody: " < < func - > hasBody ( ) < < std : : endl ;
std : : cout < < " isInline: " < < func - > isInline ( ) < < std : : endl ;
std : : cout < < " isConst: " < < func - > isConst ( ) < < std : : endl ;
2019-07-04 12:32:32 +02:00
std : : cout < < " hasVirtualSpecifier: " < < func - > hasVirtualSpecifier ( ) < < std : : endl ;
2015-01-09 21:34:57 +01:00
std : : cout < < " isPure: " < < func - > isPure ( ) < < std : : endl ;
std : : cout < < " isStatic: " < < func - > isStatic ( ) < < std : : endl ;
std : : cout < < " isStaticLocal: " < < func - > isStaticLocal ( ) < < std : : endl ;
std : : cout < < " isExtern: " < < func - > isExtern ( ) < < std : : endl ;
std : : cout < < " isFriend: " < < func - > isFriend ( ) < < std : : endl ;
std : : cout < < " isExplicit: " < < func - > isExplicit ( ) < < std : : endl ;
std : : cout < < " isDefault: " < < func - > isDefault ( ) < < std : : endl ;
std : : cout < < " isDelete: " < < func - > isDelete ( ) < < std : : endl ;
2018-12-13 06:34:10 +01:00
std : : cout < < " hasOverrideSpecifier: " < < func - > hasOverrideSpecifier ( ) < < std : : endl ;
std : : cout < < " hasFinalSpecifier: " < < func - > hasFinalSpecifier ( ) < < std : : endl ;
2015-01-09 21:34:57 +01:00
std : : cout < < " isNoExcept: " < < func - > isNoExcept ( ) < < std : : endl ;
std : : cout < < " isThrow: " < < func - > isThrow ( ) < < std : : endl ;
std : : cout < < " isOperator: " < < func - > isOperator ( ) < < std : : endl ;
2016-01-02 18:53:51 +01:00
std : : cout < < " hasLvalRefQual: " < < func - > hasLvalRefQualifier ( ) < < std : : endl ;
std : : cout < < " hasRvalRefQual: " < < func - > hasRvalRefQualifier ( ) < < std : : endl ;
2016-08-02 08:58:11 +02:00
std : : cout < < " isVariadic: " < < func - > isVariadic ( ) < < std : : endl ;
2018-05-10 07:40:01 +02:00
std : : cout < < " isVolatile: " < < func - > isVolatile ( ) < < std : : endl ;
2018-12-13 06:34:10 +01:00
std : : cout < < " hasTrailingReturnType: " < < func - > hasTrailingReturnType ( ) < < std : : endl ;
2015-01-09 21:34:57 +01:00
std : : cout < < " attributes: " ;
if ( func - > isAttributeConst ( ) )
std : : cout < < " const " ;
if ( func - > isAttributePure ( ) )
std : : cout < < " pure " ;
if ( func - > isAttributeNoreturn ( ) )
std : : cout < < " noreturn " ;
if ( func - > isAttributeNothrow ( ) )
std : : cout < < " nothrow " ;
if ( func - > isAttributeConstructor ( ) )
std : : cout < < " constructor " ;
if ( func - > isAttributeDestructor ( ) )
std : : cout < < " destructor " ;
2018-05-29 21:43:56 +02:00
if ( func - > isAttributeNodiscard ( ) )
std : : cout < < " nodiscard " ;
2015-01-09 21:34:57 +01:00
std : : cout < < std : : endl ;
2014-04-10 16:17:10 +02:00
std : : cout < < " noexceptArg: " < < ( func - > noexceptArg ? func - > noexceptArg - > str ( ) : " none " ) < < std : : endl ;
std : : cout < < " throwArg: " < < ( func - > throwArg ? func - > throwArg - > str ( ) : " none " ) < < std : : endl ;
2018-06-16 16:10:28 +02:00
std : : cout < < " tokenDef: " < < tokenToString ( func - > tokenDef , mTokenizer ) < < std : : endl ;
std : : cout < < " argDef: " < < tokenToString ( func - > argDef , mTokenizer ) < < std : : endl ;
2013-09-03 10:48:01 +02:00
if ( ! func - > isConstructor ( ) & & ! func - > isDestructor ( ) )
2018-06-16 16:10:28 +02:00
std : : cout < < " retDef: " < < tokenToString ( func - > retDef , mTokenizer ) < < std : : endl ;
2017-04-08 01:57:10 +02:00
if ( func - > retDef ) {
std : : cout < < " " ;
2018-12-13 06:34:10 +01:00
for ( const Token * tok = func - > retDef ; tok & & tok ! = func - > tokenDef & & ! Token : : Match ( tok , " {|;|override|final " ) ; tok = tok - > next ( ) )
2017-04-08 01:57:10 +02:00
std : : cout < < " " < < tokenType ( tok ) ;
std : : cout < < std : : endl ;
}
2013-08-26 06:03:26 +02:00
std : : cout < < " retType: " < < func - > retType < < std : : endl ;
2017-04-08 01:57:10 +02:00
if ( func - > tokenDef - > next ( ) - > valueType ( ) ) {
const ValueType * valueType = func - > tokenDef - > next ( ) - > valueType ( ) ;
std : : cout < < " valueType: " < < valueType < < std : : endl ;
if ( valueType ) {
std : : cout < < " " < < valueType - > str ( ) < < std : : endl ;
}
}
2015-01-08 05:45:31 +01:00
if ( func - > hasBody ( ) ) {
2018-06-16 16:10:28 +02:00
std : : cout < < " token: " < < tokenToString ( func - > token , mTokenizer ) < < std : : endl ;
std : : cout < < " arg: " < < tokenToString ( func - > arg , mTokenizer ) < < std : : endl ;
2012-03-23 17:59:51 +01:00
}
2018-06-16 16:10:28 +02:00
std : : cout < < " nestedIn: " < < scopeToString ( func - > nestedIn , mTokenizer ) < < std : : endl ;
std : : cout < < " functionScope: " < < scopeToString ( func - > functionScope , mTokenizer ) < < std : : endl ;
2012-01-05 18:22:54 +01:00
2022-06-08 16:58:57 +02:00
for ( auto var = func - > argumentList . cbegin ( ) ; var ! = func - > argumentList . cend ( ) ; + + var ) {
2012-01-05 18:22:54 +01:00
std : : cout < < " Variable: " < < & * var < < std : : endl ;
printVariable ( & * var , " " ) ;
}
}
2022-06-08 16:58:57 +02:00
for ( auto var = scope - > varlist . cbegin ( ) ; var ! = scope - > varlist . cend ( ) ; + + var ) {
2012-01-05 18:22:54 +01:00
std : : cout < < " Variable: " < < & * var < < std : : endl ;
printVariable ( & * var , " " ) ;
}
2016-04-22 06:02:54 +02:00
if ( scope - > type = = Scope : : eEnum ) {
std : : cout < < " enumType: " ;
2021-01-16 19:03:28 +01:00
if ( scope - > enumType ) {
2021-02-21 17:21:33 +01:00
std : : cout < < scope - > enumType - > stringify ( false , true , false ) ;
2021-01-16 19:03:28 +01:00
} else
2016-04-22 06:02:54 +02:00
std : : cout < < " int " ;
std : : cout < < std : : endl ;
std : : cout < < " enumClass: " < < scope - > enumClass < < std : : endl ;
2020-01-26 07:31:04 +01:00
for ( const Enumerator & enumerator : scope - > enumeratorList ) {
std : : cout < < " Enumerator: " < < enumerator . name - > str ( ) < < " = " ;
if ( enumerator . value_known )
std : : cout < < enumerator . value ;
if ( enumerator . start ) {
const Token * tok = enumerator . start ;
std : : cout < < ( enumerator . value_known ? " " : " " ) < < " [ " < < tok - > str ( ) ;
while ( tok & & tok ! = enumerator . end ) {
2016-04-22 06:02:54 +02:00
if ( tok - > next ( ) )
std : : cout < < " " < < tok - > next ( ) - > str ( ) ;
tok = tok - > next ( ) ;
}
std : : cout < < " ] " ;
}
std : : cout < < std : : endl ;
}
}
2012-01-05 18:22:54 +01:00
std : : cout < < " nestedIn: " < < scope - > nestedIn ;
2012-01-05 18:24:27 +01:00
if ( scope - > nestedIn ) {
std : : cout < < " " < < scope - > nestedIn - > type < < " "
2012-01-23 04:32:53 +01:00
< < scope - > nestedIn - > className ;
2012-01-05 18:22:54 +01:00
}
2012-01-23 04:32:53 +01:00
std : : cout < < std : : endl ;
2012-01-05 18:22:54 +01:00
2013-03-14 06:34:12 +01:00
std : : cout < < " definedType: " < < scope - > definedType < < std : : endl ;
2013-03-05 15:28:40 +01:00
2012-01-05 18:22:54 +01:00
std : : cout < < " nestedList[ " < < scope - > nestedList . size ( ) < < " ] = ( " ;
2013-03-05 15:28:40 +01:00
std : : size_t count = scope - > nestedList . size ( ) ;
2022-06-08 16:58:57 +02:00
for ( std : : vector < Scope * > : : const_iterator nsi = scope - > nestedList . cbegin ( ) ; nsi ! = scope - > nestedList . cend ( ) ; + + nsi ) {
2012-11-30 06:03:58 +01:00
std : : cout < < " " < < ( * nsi ) < < " " < < ( * nsi ) - > type < < " " < < ( * nsi ) - > className ;
2012-01-05 18:22:54 +01:00
if ( count - - > 1 )
std : : cout < < " , " ;
}
std : : cout < < " ) " < < std : : endl ;
2022-06-08 16:58:57 +02:00
for ( auto use = scope - > usingList . cbegin ( ) ; use ! = scope - > usingList . cend ( ) ; + + use ) {
2012-12-20 06:53:04 +01:00
std : : cout < < " using: " < < use - > scope < < " " < < use - > start - > strAt ( 2 ) ;
const Token * tok1 = use - > start - > tokAt ( 3 ) ;
2012-01-05 18:24:27 +01:00
while ( tok1 & & tok1 - > str ( ) = = " :: " ) {
2012-01-05 18:22:54 +01:00
std : : cout < < " :: " < < tok1 - > strAt ( 1 ) ;
tok1 = tok1 - > tokAt ( 2 ) ;
}
2018-06-16 16:10:28 +02:00
std : : cout < < " " < < mTokenizer - > list . fileLine ( use - > start ) < < std : : endl ;
2012-01-05 18:22:54 +01:00
}
2018-06-16 16:10:28 +02:00
std : : cout < < " functionOf: " < < scopeToString ( scope - > functionOf , mTokenizer ) < < std : : endl ;
2012-01-05 18:22:54 +01:00
std : : cout < < " function: " < < scope - > function ;
2015-01-09 21:34:57 +01:00
if ( scope - > function )
std : : cout < < " " < < scope - > function - > name ( ) ;
2012-01-05 18:22:54 +01:00
std : : cout < < std : : endl ;
}
2013-03-05 15:28:40 +01:00
for ( std : : list < Type > : : const_iterator type = typeList . begin ( ) ; type ! = typeList . end ( ) ; + + type ) {
2013-08-19 06:06:53 +02:00
std : : cout < < " Type: " < < & ( * type ) < < std : : endl ;
std : : cout < < " name: " < < type - > name ( ) < < std : : endl ;
2018-06-16 16:10:28 +02:00
std : : cout < < " classDef: " < < tokenToString ( type - > classDef , mTokenizer ) < < std : : endl ;
2013-03-05 15:28:40 +01:00
std : : cout < < " classScope: " < < type - > classScope < < std : : endl ;
2018-09-24 06:40:20 +02:00
std : : cout < < " enclosingScope: " < < type - > enclosingScope ;
if ( type - > enclosingScope ) {
std : : cout < < " " < < type - > enclosingScope - > type < < " "
< < type - > enclosingScope - > className ;
}
std : : cout < < std : : endl ;
2019-08-02 21:14:29 +02:00
std : : cout < < " needInitialization: " < < ( type - > needInitialization = = Type : : NeedInitialization : : Unknown ? " Unknown " :
2021-08-07 20:51:18 +02:00
type - > needInitialization = = Type : : NeedInitialization : : True ? " True " :
type - > needInitialization = = Type : : NeedInitialization : : False ? " False " :
" Invalid " ) < < std : : endl ;
2013-03-05 15:28:40 +01:00
std : : cout < < " derivedFrom[ " < < type - > derivedFrom . size ( ) < < " ] = ( " ;
std : : size_t count = type - > derivedFrom . size ( ) ;
2019-09-19 20:29:33 +02:00
for ( const Type : : BaseInfo & i : type - > derivedFrom ) {
if ( i . isVirtual )
2013-03-05 15:28:40 +01:00
std : : cout < < " Virtual " ;
2019-09-19 20:29:33 +02:00
std : : cout < < ( i . access = = AccessControl : : Public ? " Public " :
i . access = = AccessControl : : Protected ? " Protected " :
i . access = = AccessControl : : Private ? " Private " :
2013-03-05 15:28:40 +01:00
" Unknown " ) ;
2019-09-19 20:29:33 +02:00
if ( i . type )
std : : cout < < " " < < i . type ;
2013-03-05 15:28:40 +01:00
else
std : : cout < < " Unknown " ;
2019-09-19 20:29:33 +02:00
std : : cout < < " " < < i . name ;
2013-03-05 15:28:40 +01:00
if ( count - - > 1 )
std : : cout < < " , " ;
}
std : : cout < < " ) " < < std : : endl ;
std : : cout < < " friendList[ " < < type - > friendList . size ( ) < < " ] = ( " ;
2018-05-14 12:18:59 +02:00
for ( size_t i = 0 ; i < type - > friendList . size ( ) ; i + + ) {
if ( type - > friendList [ i ] . type )
std : : cout < < type - > friendList [ i ] . type ;
2013-03-05 15:28:40 +01:00
else
std : : cout < < " Unknown " ;
2018-05-14 15:24:09 +02:00
std : : cout < < ' ' ;
if ( type - > friendList [ i ] . nameEnd )
std : : cout < < type - > friendList [ i ] . nameEnd - > str ( ) ;
2018-05-14 12:18:59 +02:00
if ( i + 1 < type - > friendList . size ( ) )
2018-05-14 15:24:09 +02:00
std : : cout < < ' , ' ;
2013-03-05 15:28:40 +01:00
}
std : : cout < < " ) " < < std : : endl ;
}
2018-06-16 20:31:47 +02:00
for ( std : : size_t i = 1 ; i < mVariableList . size ( ) ; i + + ) {
std : : cout < < " mVariableList[ " < < i < < " ]: " < < mVariableList [ i ] ;
if ( mVariableList [ i ] ) {
std : : cout < < " " < < mVariableList [ i ] - > name ( ) < < " "
< < mTokenizer - > list . fileLine ( mVariableList [ i ] - > nameToken ( ) ) ;
2013-03-13 06:31:13 +01:00
}
std : : cout < < std : : endl ;
2012-01-05 18:22:54 +01:00
}
2015-01-09 21:34:57 +01:00
std : : cout < < std : : resetiosflags ( std : : ios : : boolalpha ) ;
2012-01-05 18:22:54 +01:00
}
2014-07-14 15:51:45 +02:00
void SymbolDatabase : : printXml ( std : : ostream & out ) const
2014-07-13 17:21:45 +02:00
{
2015-01-09 21:34:57 +01:00
out < < std : : setiosflags ( std : : ios : : boolalpha ) ;
2018-04-10 11:10:10 +02:00
std : : set < const Variable * > variables ;
2014-07-13 17:21:45 +02:00
// Scopes..
2014-07-14 15:51:45 +02:00
out < < " <scopes> " < < std : : endl ;
2014-07-13 17:21:45 +02:00
for ( std : : list < Scope > : : const_iterator scope = scopeList . begin ( ) ; scope ! = scopeList . end ( ) ; + + scope ) {
2014-07-14 15:51:45 +02:00
out < < " <scope " ;
out < < " id= \" " < < & * scope < < " \" " ;
out < < " type= \" " < < scope - > type < < " \" " ;
2014-07-13 17:21:45 +02:00
if ( ! scope - > className . empty ( ) )
2015-12-07 18:11:13 +01:00
out < < " className= \" " < < ErrorLogger : : toxml ( scope - > className ) < < " \" " ;
2018-04-27 22:36:30 +02:00
if ( scope - > bodyStart )
out < < " bodyStart= \" " < < scope - > bodyStart < < ' \" ' ;
if ( scope - > bodyEnd )
out < < " bodyEnd= \" " < < scope - > bodyEnd < < ' \" ' ;
2014-07-14 15:51:45 +02:00
if ( scope - > nestedIn )
out < < " nestedIn= \" " < < scope - > nestedIn < < " \" " ;
2014-07-20 11:44:01 +02:00
if ( scope - > function )
out < < " function= \" " < < scope - > function < < " \" " ;
2022-07-20 07:23:19 +02:00
if ( scope - > definedType )
out < < " definedType= \" " < < scope - > definedType < < " \" " ;
2014-07-20 11:44:01 +02:00
if ( scope - > functionList . empty ( ) & & scope - > varlist . empty ( ) )
2014-07-14 15:51:45 +02:00
out < < " /> " < < std : : endl ;
2014-07-20 11:44:01 +02:00
else {
2014-07-14 15:51:45 +02:00
out < < ' > ' < < std : : endl ;
if ( ! scope - > functionList . empty ( ) ) {
out < < " <functionList> " < < std : : endl ;
for ( std : : list < Function > : : const_iterator function = scope - > functionList . begin ( ) ; function ! = scope - > functionList . end ( ) ; + + function ) {
2021-06-27 10:51:32 +02:00
out < < " <function id= \" " < < & * function
< < " \" token= \" " < < function - > token
< < " \" tokenDef= \" " < < function - > tokenDef
< < " \" name= \" " < < ErrorLogger : : toxml ( function - > name ( ) ) < < ' \" ' ;
2018-04-30 16:52:51 +02:00
out < < " type= \" " < < ( function - > type = = Function : : eConstructor ? " Constructor " :
function - > type = = Function : : eCopyConstructor ? " CopyConstructor " :
function - > type = = Function : : eMoveConstructor ? " MoveConstructor " :
function - > type = = Function : : eOperatorEqual ? " OperatorEqual " :
function - > type = = Function : : eDestructor ? " Destructor " :
function - > type = = Function : : eFunction ? " Function " :
2019-07-11 08:25:25 +02:00
function - > type = = Function : : eLambda ? " Lambda " :
2018-04-30 16:52:51 +02:00
" Unknown " ) < < ' \" ' ;
2018-04-13 21:15:43 +02:00
if ( function - > nestedIn - > definedType ) {
2019-07-04 12:32:32 +02:00
if ( function - > hasVirtualSpecifier ( ) )
out < < " hasVirtualSpecifier= \" true \" " ;
2018-04-13 21:15:43 +02:00
else if ( function - > isImplicitlyVirtual ( ) )
out < < " isImplicitlyVirtual= \" true \" " ;
}
2022-07-22 10:36:43 +02:00
if ( function - > access = = AccessControl : : Public | | function - > access = = AccessControl : : Protected | | function - > access = = AccessControl : : Private )
out < < " access= \" " < < accessControlToString ( function - > access ) < < " \" " ;
2021-07-18 21:18:07 +02:00
if ( function - > isInlineKeyword ( ) )
out < < " isInlineKeyword= \" true \" " ;
2019-10-26 08:32:46 +02:00
if ( function - > isStatic ( ) )
out < < " isStatic= \" true \" " ;
2022-09-03 12:09:20 +02:00
if ( function - > isAttributeNoreturn ( ) )
out < < " isAttributeNoreturn= \" true \" " ;
2022-07-20 07:23:19 +02:00
if ( const Function * overriddenFunction = function - > getOverriddenFunction ( ) )
out < < " overriddenFunction= \" " < < overriddenFunction < < " \" " ;
2014-07-14 15:51:45 +02:00
if ( function - > argCount ( ) = = 0U )
out < < " /> " < < std : : endl ;
else {
out < < " > " < < std : : endl ;
for ( unsigned int argnr = 0 ; argnr < function - > argCount ( ) ; + + argnr ) {
const Variable * arg = function - > getArgumentVar ( argnr ) ;
2014-07-14 18:35:15 +02:00
out < < " <arg nr= \" " < < argnr + 1 < < " \" variable= \" " < < arg < < " \" /> " < < std : : endl ;
2018-04-10 11:10:10 +02:00
variables . insert ( arg ) ;
2014-07-14 15:51:45 +02:00
}
out < < " </function> " < < std : : endl ;
}
}
out < < " </functionList> " < < std : : endl ;
}
2014-07-14 19:25:30 +02:00
if ( ! scope - > varlist . empty ( ) ) {
out < < " <varlist> " < < std : : endl ;
for ( std : : list < Variable > : : const_iterator var = scope - > varlist . begin ( ) ; var ! = scope - > varlist . end ( ) ; + + var )
out < < " <var id= \" " < < & * var < < " \" /> " < < std : : endl ;
out < < " </varlist> " < < std : : endl ;
}
out < < " </scope> " < < std : : endl ;
2014-07-14 15:51:45 +02:00
}
2014-07-13 17:21:45 +02:00
}
2014-07-14 15:51:45 +02:00
out < < " </scopes> " < < std : : endl ;
2014-07-14 18:35:15 +02:00
2022-07-20 07:23:19 +02:00
if ( ! typeList . empty ( ) ) {
out < < " <types> \n " ;
for ( const Type & type : typeList ) {
out < < " <type id= \" " < < & type < < " \" classScope= \" " < < type . classScope < < " \" " ;
if ( type . derivedFrom . empty ( ) ) {
out < < " /> \n " ;
continue ;
}
out < < " > \n " ;
for ( const Type : : BaseInfo & baseInfo : type . derivedFrom ) {
out < < " <derivedFrom "
< < " access= \" " < < accessControlToString ( baseInfo . access ) < < " \" "
< < " type= \" " < < baseInfo . type < < " \" "
< < " isVirtual= \" " < < ( baseInfo . isVirtual ? " true " : " false " ) < < " \" "
2022-07-21 15:57:41 +02:00
< < " nameTok= \" " < < baseInfo . nameTok < < " \" "
2022-07-20 07:23:19 +02:00
< < " /> \n " ;
}
out < < " </type> \n " ;
}
out < < " </types> \n " ;
}
2014-07-14 18:35:15 +02:00
// Variables..
2018-06-16 20:31:47 +02:00
for ( const Variable * var : mVariableList )
2018-04-10 11:10:10 +02:00
variables . insert ( var ) ;
2014-07-14 18:35:15 +02:00
out < < " <variables> " < < std : : endl ;
2018-04-10 11:10:10 +02:00
for ( const Variable * var : variables ) {
2014-07-14 19:17:39 +02:00
if ( ! var )
continue ;
2014-07-14 18:35:15 +02:00
out < < " <var id= \" " < < var < < ' \" ' ;
out < < " nameToken= \" " < < var - > nameToken ( ) < < ' \" ' ;
out < < " typeStartToken= \" " < < var - > typeStartToken ( ) < < ' \" ' ;
out < < " typeEndToken= \" " < < var - > typeEndToken ( ) < < ' \" ' ;
2018-06-19 08:50:32 +02:00
out < < " access= \" " < < accessControlToString ( var - > mAccess ) < < ' \" ' ;
out < < " scope= \" " < < var - > scope ( ) < < ' \" ' ;
2021-02-06 19:06:05 +01:00
if ( var - > valueType ( ) )
out < < " constness= \" " < < var - > valueType ( ) - > constness < < ' \" ' ;
2015-01-09 21:34:57 +01:00
out < < " isArray= \" " < < var - > isArray ( ) < < ' \" ' ;
out < < " isClass= \" " < < var - > isClass ( ) < < ' \" ' ;
2018-03-14 11:54:23 +01:00
out < < " isConst= \" " < < var - > isConst ( ) < < ' \" ' ;
2017-04-17 07:45:27 +02:00
out < < " isExtern= \" " < < var - > isExtern ( ) < < ' \" ' ;
2015-01-09 21:34:57 +01:00
out < < " isPointer= \" " < < var - > isPointer ( ) < < ' \" ' ;
out < < " isReference= \" " < < var - > isReference ( ) < < ' \" ' ;
out < < " isStatic= \" " < < var - > isStatic ( ) < < ' \" ' ;
2021-11-19 17:21:05 +01:00
out < < " isVolatile= \" " < < var - > isVolatile ( ) < < ' \" ' ;
2014-07-14 18:35:15 +02:00
out < < " /> " < < std : : endl ;
}
out < < " </variables> " < < std : : endl ;
2015-01-09 21:34:57 +01:00
out < < std : : resetiosflags ( std : : ios : : boolalpha ) ;
2014-07-13 17:21:45 +02:00
}
2011-01-15 07:59:37 +01:00
//---------------------------------------------------------------------------
2015-12-18 08:24:02 +01:00
static const Type * findVariableTypeIncludingUsedNamespaces ( const SymbolDatabase * symbolDatabase , const Scope * scope , const Token * typeTok )
{
const Type * argType = symbolDatabase - > findVariableType ( scope , typeTok ) ;
if ( argType )
return argType ;
// look for variable type in any using namespace in this scope or above
while ( scope ) {
2018-04-23 21:45:25 +02:00
for ( const Scope : : UsingInfo & ui : scope - > usingList ) {
if ( ui . scope ) {
argType = symbolDatabase - > findVariableType ( ui . scope , typeTok ) ;
2015-12-18 08:24:02 +01:00
if ( argType )
return argType ;
}
}
scope = scope - > nestedIn ;
}
return nullptr ;
}
//---------------------------------------------------------------------------
2012-04-27 21:51:13 +02:00
void Function : : addArguments ( const SymbolDatabase * symbolDatabase , const Scope * scope )
2011-02-26 21:51:12 +01:00
{
// check for non-empty argument list "( ... )"
2012-10-30 15:48:06 +01:00
const Token * start = arg ? arg : argDef ;
2019-07-05 12:30:42 +02:00
if ( ! Token : : simpleMatch ( start , " ( " ) )
return ;
2017-07-09 13:09:36 +02:00
if ( ! ( start & & start - > link ( ) ! = start - > next ( ) & & ! Token : : simpleMatch ( start , " ( void ) " ) ) )
return ;
2014-09-19 09:29:31 +02:00
2017-07-09 13:09:36 +02:00
unsigned int count = 0 ;
2011-02-26 21:51:12 +01:00
2017-07-09 13:09:36 +02:00
for ( const Token * tok = start - > next ( ) ; tok ; tok = tok - > next ( ) ) {
if ( Token : : Match ( tok , " ,|) " ) )
return ; // Syntax error
2011-03-03 03:08:27 +01:00
2017-07-09 13:09:36 +02:00
const Token * startTok = tok ;
const Token * endTok = nullptr ;
const Token * nameTok = nullptr ;
2011-04-29 02:53:31 +02:00
2017-07-09 13:09:36 +02:00
do {
2020-01-29 17:29:28 +01:00
if ( Token : : simpleMatch ( tok , " decltype ( " ) ) {
tok = tok - > linkAt ( 1 ) - > next ( ) ;
continue ;
}
2019-03-30 07:44:36 +01:00
if ( tok ! = startTok & & ! nameTok & & Token : : Match ( tok , " ( & %var% ) [ " ) ) {
nameTok = tok - > tokAt ( 2 ) ;
endTok = nameTok - > previous ( ) ;
tok = tok - > link ( ) ;
2020-05-02 17:04:54 +02:00
} else if ( tok ! = startTok & & ! nameTok & & Token : : Match ( tok , " ( * %var% ) ( ) [ , ) ] " )) {
nameTok = tok - > tokAt ( 2 ) ;
endTok = nameTok - > previous ( ) ;
tok = tok - > link ( ) - > tokAt ( 2 ) ;
2021-08-15 07:48:01 +02:00
} else if ( tok ! = startTok & & ! nameTok & & Token : : Match ( tok , " ( * %var% ) [ " )) {
nameTok = tok - > tokAt ( 2 ) ;
endTok = nameTok - > previous ( ) ;
tok = tok - > link ( ) ;
2019-03-30 07:44:36 +01:00
} else if ( tok - > varId ( ) ! = 0 ) {
2017-07-09 13:09:36 +02:00
nameTok = tok ;
endTok = tok - > previous ( ) ;
} else if ( tok - > str ( ) = = " [ " ) {
// skip array dimension(s)
tok = tok - > link ( ) ;
while ( tok - > next ( ) - > str ( ) = = " [ " )
tok = tok - > next ( ) - > link ( ) ;
} else if ( tok - > str ( ) = = " < " ) {
tok = tok - > link ( ) ;
if ( ! tok ) // something is wrong so just bail out
2011-04-29 02:53:31 +02:00
return ;
2017-07-09 13:09:36 +02:00
}
2011-02-26 21:51:12 +01:00
2017-07-09 13:09:36 +02:00
tok = tok - > next ( ) ;
if ( ! tok ) // something is wrong so just bail
return ;
} while ( tok - > str ( ) ! = " , " & & tok - > str ( ) ! = " ) " & & tok - > str ( ) ! = " = " ) ;
const Token * typeTok = startTok ;
// skip over stuff to get to type
2018-05-10 07:40:01 +02:00
while ( Token : : Match ( typeTok , " const|volatile|enum|struct|:: " ) )
2017-07-09 13:09:36 +02:00
typeTok = typeTok - > next ( ) ;
2018-01-18 08:51:35 +01:00
if ( Token : : Match ( typeTok , " ,|) " ) ) { // #8333
2018-06-16 16:10:28 +02:00
symbolDatabase - > mTokenizer - > syntaxError ( typeTok ) ;
2018-01-18 08:51:35 +01:00
}
2017-07-09 13:09:36 +02:00
// skip over qualification
while ( Token : : Match ( typeTok , " %type% :: " ) )
typeTok = typeTok - > tokAt ( 2 ) ;
// check for argument with no name or missing varid
if ( ! endTok ) {
2018-05-10 07:40:01 +02:00
if ( tok - > previous ( ) - > isName ( ) & & ! Token : : Match ( tok - > tokAt ( - 1 ) , " const|volatile " ) ) {
2017-07-09 13:09:36 +02:00
if ( tok - > previous ( ) ! = typeTok ) {
nameTok = tok - > previous ( ) ;
endTok = nameTok - > previous ( ) ;
if ( hasBody ( ) )
2020-12-31 19:24:16 +01:00
symbolDatabase - > debugMessage ( nameTok , " varid0 " , " Function::addArguments found argument \' " + nameTok - > str ( ) + " \' with varid 0. " ) ;
2011-10-13 20:53:06 +02:00
} else
2017-07-09 13:09:36 +02:00
endTok = typeTok ;
} else
endTok = tok - > previous ( ) ;
}
2011-02-26 21:51:12 +01:00
2017-07-09 13:09:36 +02:00
const : : Type * argType = nullptr ;
if ( ! typeTok - > isStandardType ( ) ) {
argType = findVariableTypeIncludingUsedNamespaces ( symbolDatabase , scope , typeTok ) ;
2016-04-22 06:02:54 +02:00
2017-07-09 13:09:36 +02:00
// save type
const_cast < Token * > ( typeTok ) - > type ( argType ) ;
}
2011-02-26 21:51:12 +01:00
2017-07-09 13:09:36 +02:00
// skip default values
if ( tok - > str ( ) = = " = " ) {
do {
if ( tok - > link ( ) & & Token : : Match ( tok , " [{[(<] " ) )
tok = tok - > link ( ) ;
tok = tok - > next ( ) ;
} while ( tok - > str ( ) ! = " , " & & tok - > str ( ) ! = " ) " ) ;
}
2011-03-30 05:16:13 +02:00
2017-07-09 13:09:36 +02:00
// skip over stuff before type
2018-05-10 07:40:01 +02:00
while ( Token : : Match ( startTok , " enum|struct|const|volatile " ) )
2017-07-09 13:09:36 +02:00
startTok = startTok - > next ( ) ;
2016-08-04 09:06:32 +02:00
2020-03-09 15:13:50 +01:00
if ( startTok = = nameTok )
break ;
2019-07-23 14:29:02 +02:00
argumentList . emplace_back ( nameTok , startTok , endTok , count + + , AccessControl : : Argument , argType , functionScope , symbolDatabase - > mSettings ) ;
2011-03-31 03:59:43 +02:00
2017-07-09 13:09:36 +02:00
if ( tok - > str ( ) = = " ) " ) {
2020-10-31 10:02:15 +01:00
// check for a variadic function or a variadic template function
if ( Token : : simpleMatch ( endTok , " ... " ) )
2017-07-09 13:09:36 +02:00
isVariadic ( true ) ;
2016-08-02 08:58:11 +02:00
2017-07-09 13:09:36 +02:00
break ;
2011-02-26 21:51:12 +01:00
}
2017-07-09 13:09:36 +02:00
}
2013-02-27 06:59:04 +01:00
2017-07-09 13:09:36 +02:00
// count default arguments
for ( const Token * tok = argDef - > next ( ) ; tok & & tok ! = argDef - > link ( ) ; tok = tok - > next ( ) ) {
2019-12-31 16:26:12 +01:00
if ( tok - > str ( ) = = " = " ) {
2017-07-09 13:09:36 +02:00
initArgCount + + ;
2019-12-31 16:26:12 +01:00
if ( tok - > strAt ( 1 ) = = " [ " ) {
2020-01-04 10:45:24 +01:00
const Token * lambdaStart = tok - > next ( ) ;
tok = findLambdaEndToken ( lambdaStart ) ;
if ( ! tok )
throw InternalError ( lambdaStart , " Analysis failed (lambda not recognized) . If the code is valid then please report this failure . " , InternalError::INTERNAL) ;
2019-12-31 16:26:12 +01:00
}
}
2011-02-26 21:51:12 +01:00
}
}
2012-04-17 19:50:44 +02:00
bool Function : : isImplicitlyVirtual ( bool defaultVal ) const
{
2019-07-04 12:32:32 +02:00
if ( hasVirtualSpecifier ( ) ) //If it has the virtual specifier it's definitely virtual
return true ;
if ( hasOverrideSpecifier ( ) ) //If it has the override specifier then it's either virtual or not going to compile
2012-04-17 19:50:44 +02:00
return true ;
2018-04-27 11:12:09 +02:00
bool foundAllBaseClasses = true ;
2019-07-04 12:32:32 +02:00
if ( getOverriddenFunction ( & foundAllBaseClasses ) ) //If it overrides a base class's method then it's virtual
2018-04-27 11:12:09 +02:00
return true ;
2019-07-04 12:32:32 +02:00
if ( foundAllBaseClasses ) //If we've seen all the base classes and none of the above were true then it must not be virtual
2018-04-27 11:12:09 +02:00
return false ;
2019-07-04 12:32:32 +02:00
return defaultVal ; //If we can't see all the bases classes then we can't say conclusively
2018-04-25 12:05:49 +02:00
}
2021-07-18 07:46:31 +02:00
std : : vector < const Function * > Function : : getOverloadedFunctions ( ) const
{
std : : vector < const Function * > result ;
const Scope * scope = nestedIn ;
while ( scope ) {
const bool isMemberFunction = scope - > isClassOrStruct ( ) & & ! isStatic ( ) ;
for ( std : : multimap < std : : string , const Function * > : : const_iterator it = scope - > functionMap . find ( tokenDef - > str ( ) ) ;
it ! = scope - > functionMap . end ( ) & & it - > first = = tokenDef - > str ( ) ;
+ + it ) {
const Function * func = it - > second ;
if ( isMemberFunction = = func - > isStatic ( ) )
continue ;
result . push_back ( func ) ;
}
if ( isMemberFunction )
break ;
scope = scope - > nestedIn ;
}
return result ;
}
2019-01-14 18:36:21 +01:00
const Function * Function : : getOverriddenFunction ( bool * foundAllBaseClasses ) const
2018-04-25 12:05:49 +02:00
{
2018-04-27 11:12:09 +02:00
if ( foundAllBaseClasses )
* foundAllBaseClasses = true ;
2018-04-24 13:53:58 +02:00
if ( ! nestedIn - > isClassOrStruct ( ) )
2018-04-27 11:12:09 +02:00
return nullptr ;
2019-01-14 18:36:21 +01:00
return getOverriddenFunctionRecursive ( nestedIn - > definedType , foundAllBaseClasses ) ;
2012-04-17 19:50:44 +02:00
}
2019-01-14 18:36:21 +01:00
const Function * Function : : getOverriddenFunctionRecursive ( const : : Type * baseType , bool * foundAllBaseClasses ) const
2012-04-17 19:50:44 +02:00
{
// check each base class
2019-09-25 15:25:19 +02:00
for ( const : : Type : : BaseInfo & i : baseType - > derivedFrom ) {
const : : Type * derivedFromType = i . type ;
2012-04-17 19:50:44 +02:00
// check if base class exists in database
2018-04-27 11:12:09 +02:00
if ( ! derivedFromType | | ! derivedFromType - > classScope ) {
if ( foundAllBaseClasses )
* foundAllBaseClasses = false ;
continue ;
}
2012-04-17 19:50:44 +02:00
2018-04-27 11:12:09 +02:00
const Scope * parent = derivedFromType - > classScope ;
2012-04-17 19:50:44 +02:00
2018-04-27 11:12:09 +02:00
// check if function defined in base class
2022-06-08 16:58:57 +02:00
auto range = parent - > functionMap . equal_range ( tokenDef - > str ( ) ) ;
for ( std : : multimap < std : : string , const Function * > : : const_iterator it = range . first ; it ! = range . second ; + + it ) {
2018-04-27 11:12:09 +02:00
const Function * func = it - > second ;
2019-07-04 12:32:32 +02:00
if ( func - > hasVirtualSpecifier ( ) ) { // Base is virtual and of same name
2018-04-27 11:12:09 +02:00
const Token * temp1 = func - > tokenDef - > previous ( ) ;
const Token * temp2 = tokenDef - > previous ( ) ;
bool match = true ;
// check for matching return parameters
while ( temp1 - > str ( ) ! = " virtual " ) {
if ( temp1 - > str ( ) ! = temp2 - > str ( ) & &
! ( temp1 - > str ( ) = = derivedFromType - > name ( ) & &
temp2 - > str ( ) = = baseType - > name ( ) ) ) {
match = false ;
break ;
2012-04-17 19:50:44 +02:00
}
2018-04-27 11:12:09 +02:00
temp1 = temp1 - > previous ( ) ;
temp2 = temp2 - > previous ( ) ;
2012-04-17 19:50:44 +02:00
}
2018-04-27 11:12:09 +02:00
// check for matching function parameters
2018-08-17 08:42:22 +02:00
match = match & & argsMatch ( baseType - > classScope , func - > argDef , argDef , emptyString , 0 ) ;
// check for matching cv-ref qualifiers
match = match
2018-08-17 19:55:21 +02:00
& & isConst ( ) = = func - > isConst ( )
& & isVolatile ( ) = = func - > isVolatile ( )
& & hasRvalRefQualifier ( ) = = func - > hasRvalRefQualifier ( )
& & hasLvalRefQualifier ( ) = = func - > hasLvalRefQualifier ( ) ;
2018-08-17 08:42:22 +02:00
// it's a match
if ( match ) {
2018-04-27 11:12:09 +02:00
return func ;
2014-03-22 08:49:28 +01:00
}
2014-01-05 19:10:16 +01:00
}
2018-04-27 11:12:09 +02:00
}
if ( ! derivedFromType - > derivedFrom . empty ( ) & & ! derivedFromType - > hasCircularDependencies ( ) ) {
// avoid endless recursion, see #5289 Crash: Stack overflow in isImplicitlyVirtual_rec when checking SVN and
// #5590 with a loop within the class hierarchy.
2019-01-14 18:36:21 +01:00
const Function * func = getOverriddenFunctionRecursive ( derivedFromType , foundAllBaseClasses ) ;
2021-08-07 20:51:18 +02:00
if ( func ) {
2018-04-27 11:12:09 +02:00
return func ;
}
2012-04-17 19:50:44 +02:00
}
}
2018-04-27 11:12:09 +02:00
return nullptr ;
2012-04-17 19:50:44 +02:00
}
2019-07-22 11:25:51 +02:00
const Variable * Function : : getArgumentVar ( nonneg int num ) const
2012-05-03 13:29:41 +02:00
{
2022-08-21 17:21:02 +02:00
if ( num < argumentList . size ( ) )
return & argumentList [ num ] ;
2017-08-09 20:00:26 +02:00
return nullptr ;
2012-05-03 13:29:41 +02:00
}
2012-04-17 19:50:44 +02:00
2010-11-13 08:08:45 +01:00
//---------------------------------------------------------------------------
2013-03-05 18:42:42 +01:00
Scope : : Scope ( const SymbolDatabase * check_ , const Token * classDef_ , const Scope * nestedIn_ , ScopeType type_ , const Token * start_ ) :
2011-02-26 21:53:57 +01:00
check ( check_ ) ,
classDef ( classDef_ ) ,
nestedIn ( nestedIn_ ) ,
numConstructors ( 0 ) ,
2013-04-10 21:57:22 +02:00
numCopyOrMoveConstructors ( 0 ) ,
2012-05-14 20:46:23 +02:00
type ( type_ ) ,
2014-02-16 10:32:10 +01:00
definedType ( nullptr ) ,
functionOf ( nullptr ) ,
2016-04-22 06:02:54 +02:00
function ( nullptr ) ,
enumType ( nullptr ) ,
enumClass ( false )
2021-08-10 07:00:11 +02:00
{
setBodyStartEnd ( start_ ) ;
}
2011-02-26 21:53:57 +01:00
2013-03-05 18:42:42 +01:00
Scope : : Scope ( const SymbolDatabase * check_ , const Token * classDef_ , const Scope * nestedIn_ ) :
2010-11-13 08:08:45 +01:00
check ( check_ ) ,
classDef ( classDef_ ) ,
2018-04-27 22:36:30 +02:00
bodyStart ( nullptr ) ,
bodyEnd ( nullptr ) ,
2010-11-13 08:08:45 +01:00
nestedIn ( nestedIn_ ) ,
2010-12-02 07:35:01 +01:00
numConstructors ( 0 ) ,
2013-04-10 21:57:22 +02:00
numCopyOrMoveConstructors ( 0 ) ,
2014-02-16 10:32:10 +01:00
definedType ( nullptr ) ,
functionOf ( nullptr ) ,
2016-04-22 06:02:54 +02:00
function ( nullptr ) ,
enumType ( nullptr ) ,
enumClass ( false )
2010-11-13 08:08:45 +01:00
{
2013-03-05 13:33:38 +01:00
const Token * nameTok = classDef ;
2011-10-13 20:53:06 +02:00
if ( ! classDef ) {
2011-01-17 18:29:19 +01:00
type = Scope : : eGlobal ;
2017-01-06 21:16:28 +01:00
} else if ( classDef - > str ( ) = = " class " & & check & & check - > isCPP ( ) ) {
2011-01-17 18:29:19 +01:00
type = Scope : : eClass ;
2013-03-05 13:33:38 +01:00
nameTok = nameTok - > next ( ) ;
2011-10-13 20:53:06 +02:00
} else if ( classDef - > str ( ) = = " struct " ) {
2011-01-17 18:29:19 +01:00
type = Scope : : eStruct ;
2013-03-05 13:33:38 +01:00
nameTok = nameTok - > next ( ) ;
2011-10-13 20:53:06 +02:00
} else if ( classDef - > str ( ) = = " union " ) {
2011-01-17 18:29:19 +01:00
type = Scope : : eUnion ;
2013-03-05 13:33:38 +01:00
nameTok = nameTok - > next ( ) ;
2011-10-13 20:53:06 +02:00
} else if ( classDef - > str ( ) = = " namespace " ) {
2011-01-17 18:29:19 +01:00
type = Scope : : eNamespace ;
2013-03-05 13:33:38 +01:00
nameTok = nameTok - > next ( ) ;
2016-04-22 06:02:54 +02:00
} else if ( classDef - > str ( ) = = " enum " ) {
type = Scope : : eEnum ;
nameTok = nameTok - > next ( ) ;
if ( nameTok - > str ( ) = = " class " ) {
enumClass = true ;
nameTok = nameTok - > next ( ) ;
}
2019-07-05 12:30:42 +02:00
} else if ( classDef - > str ( ) = = " [ " ) {
type = Scope : : eLambda ;
2011-10-13 20:53:06 +02:00
} else {
2011-01-17 18:29:19 +01:00
type = Scope : : eFunction ;
2010-11-13 08:08:45 +01:00
}
2013-03-05 13:33:38 +01:00
// skip over qualification if present
2018-05-01 07:32:19 +02:00
nameTok = skipScopeIdentifiers ( nameTok ) ;
2016-04-22 06:02:54 +02:00
if ( nameTok & & ( ( type = = Scope : : eEnum & & Token : : Match ( nameTok , " :|{ " ) ) | | nameTok - > str ( ) ! = " { " ) ) // anonymous and unnamed structs/unions don't have a name
2013-03-05 13:33:38 +01:00
className = nameTok - > str ( ) ;
2010-11-13 08:08:45 +01:00
}
2011-12-17 19:04:03 +01:00
bool Scope : : hasDefaultConstructor ( ) const
2010-12-21 08:13:40 +01:00
{
2011-10-13 20:53:06 +02:00
if ( numConstructors ) {
2011-01-17 18:29:19 +01:00
std : : list < Function > : : const_iterator func ;
2010-12-21 08:13:40 +01:00
2011-10-13 20:53:06 +02:00
for ( func = functionList . begin ( ) ; func ! = functionList . end ( ) ; + + func ) {
2011-03-31 03:59:43 +02:00
if ( func - > type = = Function : : eConstructor & & func - > argCount ( ) = = 0 )
2010-12-21 08:13:40 +01:00
return true ;
}
}
return false ;
}
2011-02-26 15:08:59 +01:00
AccessControl Scope : : defaultAccess ( ) const
{
2011-10-13 20:53:06 +02:00
switch ( type ) {
2011-02-26 15:08:59 +01:00
case eGlobal :
2019-07-23 14:29:02 +02:00
return AccessControl : : Global ;
2011-02-26 15:08:59 +01:00
case eClass :
2019-07-23 14:29:02 +02:00
return AccessControl : : Private ;
2011-02-26 15:08:59 +01:00
case eStruct :
2019-07-23 14:29:02 +02:00
return AccessControl : : Public ;
2011-02-26 15:08:59 +01:00
case eUnion :
2019-07-23 14:29:02 +02:00
return AccessControl : : Public ;
2011-02-26 15:08:59 +01:00
case eNamespace :
2019-07-23 14:29:02 +02:00
return AccessControl : : Namespace ;
2011-02-26 21:53:57 +01:00
default :
2019-07-23 14:29:02 +02:00
return AccessControl : : Local ;
2011-02-26 15:08:59 +01:00
}
}
2020-03-14 14:41:45 +01:00
void Scope : : addVariable ( const Token * token_ , const Token * start_ , const Token * end_ ,
2020-03-15 19:39:23 +01:00
AccessControl access_ , const Type * type_ , const Scope * scope_ , const Settings * settings )
2020-03-14 14:41:45 +01:00
{
// keep possible size_t -> int truncation outside emplace_back() to have a single line
// C4267 VC++ warning instead of several dozens lines
const int varIndex = varlist . size ( ) ;
varlist . emplace_back ( token_ , start_ , end_ , varIndex , access_ , type_ , scope_ , settings ) ;
}
2010-11-20 07:26:50 +01:00
// Get variable list..
2018-06-20 10:00:15 +02:00
void Scope : : getVariableList ( const Settings * settings )
2010-11-13 08:08:45 +01:00
{
2021-08-10 07:00:11 +02:00
if ( ! bodyStartList . empty ( ) ) {
2021-08-21 22:00:45 +02:00
for ( const Token * bs : bodyStartList )
2021-09-04 11:09:33 +02:00
getVariableList ( settings , bs - > next ( ) , bs - > link ( ) ) ;
2021-08-10 07:00:11 +02:00
}
2012-12-16 07:18:03 +01:00
// global scope
2021-08-10 07:00:11 +02:00
else if ( type = = Scope : : eGlobal )
2021-09-04 11:09:33 +02:00
getVariableList ( settings , check - > mTokenizer - > tokens ( ) , nullptr ) ;
2010-11-20 07:26:50 +01:00
2012-12-16 07:18:03 +01:00
// forward declaration
else
return ;
2021-08-10 07:00:11 +02:00
}
2012-12-16 07:18:03 +01:00
2021-09-04 11:09:33 +02:00
void Scope : : getVariableList ( const Settings * settings , const Token * start , const Token * end )
2021-08-10 07:00:11 +02:00
{
2019-10-09 22:27:48 +02:00
// Variable declared in condition: if (auto x = bar())
if ( Token : : Match ( classDef , " if|while ( %type% " ) & & Token : : simpleMatch ( classDef - > next ( ) - > astOperand2 ( ) , " = " ) ) {
checkVariable ( classDef - > tokAt ( 2 ) , defaultAccess ( ) , settings ) ;
}
2014-07-10 09:23:14 +02:00
AccessControl varaccess = defaultAccess ( ) ;
2021-09-04 11:09:33 +02:00
for ( const Token * tok = start ; tok & & tok ! = end ; tok = tok - > next ( ) ) {
2010-12-16 19:04:47 +01:00
// syntax error?
2015-03-15 12:37:50 +01:00
if ( tok - > next ( ) = = nullptr )
2010-12-16 19:04:47 +01:00
break ;
2010-11-20 07:26:50 +01:00
// Is it a function?
2011-10-13 20:53:06 +02:00
else if ( tok - > str ( ) = = " { " ) {
2019-10-10 08:17:41 +02:00
tok = tok - > link ( ) ;
2010-11-20 07:26:50 +01:00
continue ;
2010-11-13 08:08:45 +01:00
}
2010-11-20 07:26:50 +01:00
// Is it a nested class or structure?
2020-05-17 17:32:31 +02:00
else if ( tok - > isKeyword ( ) & & Token : : Match ( tok , " class|struct|union|namespace %type% :| { " )) {
2010-11-20 07:26:50 +01:00
tok = tok - > tokAt ( 2 ) ;
while ( tok & & tok - > str ( ) ! = " { " )
tok = tok - > next ( ) ;
2011-10-13 20:53:06 +02:00
if ( tok ) {
2010-11-20 07:26:50 +01:00
// skip implementation
tok = tok - > link ( ) ;
continue ;
2011-10-13 20:53:06 +02:00
} else
2010-11-20 07:26:50 +01:00
break ;
2020-05-17 17:32:31 +02:00
} else if ( tok - > isKeyword ( ) & & Token : : Match ( tok , " struct|union { " )) {
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok - > next ( ) - > link ( ) , " } %name% ;|[ " ) ) {
2014-06-25 20:41:22 +02:00
tok = tok - > next ( ) - > link ( ) - > tokAt ( 2 ) ;
continue ;
} else if ( Token : : simpleMatch ( tok - > next ( ) - > link ( ) , " } ; " )) {
tok = tok - > next ( ) ;
continue ;
}
2011-04-01 02:54:23 +02:00
}
2010-11-13 08:08:45 +01:00
// Borland C++: Skip all variables in the __published section.
2010-12-15 18:45:53 +01:00
// These are automatically initialized.
2011-10-13 20:53:06 +02:00
else if ( tok - > str ( ) = = " __published: " ) {
for ( ; tok ; tok = tok - > next ( ) ) {
2010-11-13 08:08:45 +01:00
if ( tok - > str ( ) = = " { " )
tok = tok - > link ( ) ;
if ( Token : : Match ( tok - > next ( ) , " private:|protected:|public: " ) )
break ;
}
if ( tok )
continue ;
else
break ;
}
// "private:" "public:" "protected:" etc
2011-10-13 20:53:06 +02:00
else if ( tok - > str ( ) = = " public: " ) {
2019-07-23 14:29:02 +02:00
varaccess = AccessControl : : Public ;
2010-11-20 07:26:50 +01:00
continue ;
2011-10-13 20:53:06 +02:00
} else if ( tok - > str ( ) = = " protected: " ) {
2019-07-23 14:29:02 +02:00
varaccess = AccessControl : : Protected ;
2010-11-20 07:26:50 +01:00
continue ;
2011-10-13 20:53:06 +02:00
} else if ( tok - > str ( ) = = " private: " ) {
2019-07-23 14:29:02 +02:00
varaccess = AccessControl : : Private ;
2010-11-13 08:08:45 +01:00
continue ;
2010-11-20 07:26:50 +01:00
}
2010-11-13 08:08:45 +01:00
// Is it a forward declaration?
2020-05-17 17:32:31 +02:00
else if ( tok - > isKeyword ( ) & & Token : : Match ( tok , " class|struct|union %name% ; " )) {
2010-11-13 08:08:45 +01:00
tok = tok - > tokAt ( 2 ) ;
continue ;
}
2010-11-20 07:26:50 +01:00
// Borland C++: Ignore properties..
else if ( tok - > str ( ) = = " __property " )
2010-11-13 08:08:45 +01:00
continue ;
2015-03-15 12:37:50 +01:00
// skip return, goto and delete
2020-05-17 17:32:31 +02:00
else if ( tok - > isKeyword ( ) & & Token : : Match ( tok , " return|delete|goto " ) ) {
2013-08-31 14:22:06 +02:00
while ( tok - > next ( ) & &
tok - > next ( ) - > str ( ) ! = " ; " & &
tok - > next ( ) - > str ( ) ! = " } " /* ticket #4994 */ ) {
2011-02-27 16:13:40 +01:00
tok = tok - > next ( ) ;
2013-08-31 14:22:06 +02:00
}
2011-02-27 16:13:40 +01:00
continue ;
}
2011-12-30 20:01:33 +01:00
2018-09-04 06:39:02 +02:00
// skip case/default
2020-05-17 17:32:31 +02:00
if ( tok - > isKeyword ( ) & & Token : : Match ( tok , " case|default " ) ) {
2018-09-04 06:39:02 +02:00
while ( tok - > next ( ) & & ! Token : : Match ( tok - > next ( ) , " [:;{}] " ) )
tok = tok - > next ( ) ;
continue ;
}
2010-11-20 07:26:50 +01:00
// Search for start of statement..
2019-10-09 22:27:48 +02:00
else if ( tok - > previous ( ) & & ! Token : : Match ( tok - > previous ( ) , " ; | { | } | public : | protected : | private : " ))
2010-11-13 08:08:45 +01:00
continue ;
2015-03-15 12:37:50 +01:00
else if ( tok - > str ( ) = = " ; " )
2010-12-02 07:35:01 +01:00
continue ;
2010-11-13 08:08:45 +01:00
2018-06-20 10:00:15 +02:00
tok = checkVariable ( tok , varaccess , settings ) ;
2011-03-16 03:33:14 +01:00
if ( ! tok )
break ;
2011-03-06 21:21:42 +01:00
}
}
2010-11-20 07:26:50 +01:00
2018-06-20 10:00:15 +02:00
const Token * Scope : : checkVariable ( const Token * tok , AccessControl varaccess , const Settings * settings )
2011-03-06 21:21:42 +01:00
{
2012-01-26 04:05:29 +01:00
// Is it a throw..?
2020-05-17 17:32:31 +02:00
if ( tok - > isKeyword ( ) & & Token : : Match ( tok , " throw %any% ( " ) & &
2012-01-26 04:05:29 +01:00
Token : : simpleMatch ( tok - > linkAt ( 2 ) , " ) ; " ) ) {
return tok - > linkAt ( 2 ) ;
2018-04-23 16:27:56 +02:00
}
2020-05-17 17:32:31 +02:00
if ( tok - > isKeyword ( ) & & Token : : Match ( tok , " throw %any% :: %any% ( " ) & &
Token : : simpleMatch ( tok - > linkAt ( 4 ) , " ) ; " ) ) {
2012-01-26 04:05:29 +01:00
return tok - > linkAt ( 4 ) ;
}
2012-08-12 12:01:24 +02:00
// friend?
2020-05-17 17:32:31 +02:00
if ( tok - > isKeyword ( ) & & Token : : Match ( tok , " friend %type% " ) & & tok - > next ( ) - > varId ( ) = = 0 ) {
2013-03-14 06:34:12 +01:00
const Token * next = Token : : findmatch ( tok - > tokAt ( 2 ) , " ;|{ " ) ;
if ( next & & next - > str ( ) = = " { " )
next = next - > link ( ) ;
return next ;
}
2012-08-12 12:01:24 +02:00
2018-05-10 07:40:01 +02:00
// skip const|volatile|static|mutable|extern
2022-09-26 18:21:21 +02:00
while ( tok & & tok - > isKeyword ( ) & & Token : : Match ( tok , " const|constexpr|volatile|static|mutable|extern " ) ) {
2011-03-06 21:21:42 +01:00
tok = tok - > next ( ) ;
}
2010-11-13 08:08:45 +01:00
2011-04-22 15:12:08 +02:00
// the start of the type tokens does not include the above modifiers
const Token * typestart = tok ;
2021-04-26 18:21:07 +02:00
// C++17 structured bindings
if ( settings - > standards . cpp > = Standards : : CPP17 & & Token : : Match ( tok , " auto &|&&| [ " ) ) {
const Token * typeend = Token : : findsimplematch ( typestart , " [ " ) - > previous ( ) ;
for ( tok = typeend - > tokAt ( 2 ) ; Token : : Match ( tok , " %name%|, " ) ; tok = tok - > next ( ) ) {
if ( tok - > varId ( ) )
addVariable ( tok , typestart , typeend , varaccess , nullptr , this , settings ) ;
}
return typeend - > linkAt ( 1 ) ;
}
2022-09-26 18:21:21 +02:00
while ( tok & & tok - > isKeyword ( ) & & Token : : Match ( tok , " class|struct|union|enum " ) ) {
2011-03-06 21:21:42 +01:00
tok = tok - > next ( ) ;
}
2010-11-13 08:08:45 +01:00
2014-09-19 09:29:31 +02:00
// This is the start of a statement
const Token * vartok = nullptr ;
const Token * typetok = nullptr ;
2012-05-11 17:56:47 +02:00
if ( tok & & isVariableDeclaration ( tok , vartok , typetok ) ) {
// If the vartok was set in the if-blocks above, create a entry for this variable..
tok = vartok - > next ( ) ;
2014-09-14 11:35:04 +02:00
while ( Token : : Match ( tok , " [|{ " ) )
2012-05-11 17:56:47 +02:00
tok = tok - > link ( ) - > next ( ) ;
2011-01-01 01:19:32 +01:00
2013-12-31 17:51:56 +01:00
if ( vartok - > varId ( ) = = 0 ) {
if ( ! vartok - > isBoolean ( ) )
2020-12-31 19:24:16 +01:00
check - > debugMessage ( vartok , " varid0 " , " Scope::checkVariable found variable \' " + vartok - > str ( ) + " \' with varid 0. " ) ;
2013-12-31 17:51:56 +01:00
return tok ;
}
2010-11-13 08:08:45 +01:00
2014-02-16 10:32:10 +01:00
const Type * vType = nullptr ;
2010-12-02 07:35:01 +01:00
2012-12-20 06:53:04 +01:00
if ( typetok ) {
2015-12-18 08:24:02 +01:00
vType = findVariableTypeIncludingUsedNamespaces ( check , this , typetok ) ;
2016-04-22 06:02:54 +02:00
const_cast < Token * > ( typetok ) - > type ( vType ) ;
2012-12-20 06:53:04 +01:00
}
2010-12-02 07:35:01 +01:00
2016-08-04 09:06:32 +02:00
// skip "enum" or "struct"
if ( Token : : Match ( typestart , " enum|struct " ) )
typestart = typestart - > next ( ) ;
2018-06-20 10:00:15 +02:00
addVariable ( vartok , typestart , vartok - > previous ( ) , varaccess , vType , this , settings ) ;
2010-12-02 07:35:01 +01:00
}
2011-03-06 21:21:42 +01:00
return tok ;
2010-12-02 07:35:01 +01:00
}
2011-09-03 03:07:29 +02:00
const Variable * Scope : : getVariable ( const std : : string & varname ) const
{
2022-10-11 20:47:07 +02:00
for ( const Variable & var : varlist ) {
if ( var . name ( ) = = varname )
return & var ;
}
if ( definedType ) {
for ( const Type : : BaseInfo & baseInfo : definedType - > derivedFrom ) {
if ( baseInfo . type & & baseInfo . type - > classScope ) {
if ( const Variable * var = baseInfo . type - > classScope - > getVariable ( varname ) )
return var ;
}
}
2011-09-03 03:07:29 +02:00
}
2014-02-16 10:32:10 +01:00
return nullptr ;
2011-09-03 03:07:29 +02:00
}
2012-02-11 12:26:48 +01:00
static const Token * skipPointers ( const Token * tok )
2010-12-30 22:57:43 +01:00
{
2021-08-07 20:51:18 +02:00
while ( Token : : Match ( tok , " *|&|&& " ) | | ( Token : : Match ( tok , " ( [*&] " ) & & Token : : Match ( tok - > link ( ) - > next ( ) , " (|[ " ) ) ) {
2012-02-11 12:26:48 +01:00
tok = tok - > next ( ) ;
2014-04-12 11:43:10 +02:00
if ( tok - > strAt ( - 1 ) = = " ( " & & Token : : Match ( tok , " %type% :: " ) )
tok = tok - > tokAt ( 2 ) ;
2010-12-30 09:46:44 +01:00
}
2010-12-30 22:57:43 +01:00
2020-10-02 08:25:43 +02:00
if ( Token : : simpleMatch ( tok , " ( * " ) & & Token : : simpleMatch ( tok - > link ( ) - > previous ( ) , " ] ) ; " ) ) {
const Token * tok2 = skipPointers ( tok - > next ( ) ) ;
if ( Token : : Match ( tok2 , " %name% [ " ) & & Token : : simpleMatch ( tok2 - > linkAt ( 1 ) , " ] ) ; " ) )
return tok2 ;
}
2012-02-11 12:26:48 +01:00
return tok ;
2010-12-30 22:57:43 +01:00
}
2018-09-25 06:19:26 +02:00
static const Token * skipPointersAndQualifiers ( const Token * tok )
{
tok = skipPointers ( tok ) ;
2022-05-10 20:43:11 +02:00
while ( Token : : Match ( tok , " const|static|volatile " ) ) {
2018-09-25 06:19:26 +02:00
tok = tok - > next ( ) ;
tok = skipPointers ( tok ) ;
}
return tok ;
}
2016-01-30 14:04:48 +01:00
bool Scope : : isVariableDeclaration ( const Token * const tok , const Token * & vartok , const Token * & typetok ) const
2010-12-30 22:57:43 +01:00
{
2022-01-06 15:23:43 +01:00
if ( ! tok )
return false ;
2018-06-16 16:10:28 +02:00
const bool isCPP = check & & check - > mTokenizer - > isCPP ( ) ;
2018-01-10 22:16:18 +01:00
if ( isCPP & & Token : : Match ( tok , " throw|new " ) )
return false ;
2018-06-16 16:10:28 +02:00
const bool isCPP11 = isCPP & & check - > mSettings - > standards . cpp > = Standards : : CPP11 ;
2018-01-10 22:16:18 +01:00
if ( isCPP11 & & tok - > str ( ) = = " using " )
2012-01-28 01:24:01 +01:00
return false ;
2011-01-02 00:36:22 +01:00
const Token * localTypeTok = skipScopeIdentifiers ( tok ) ;
2014-02-16 10:32:10 +01:00
const Token * localVarTok = nullptr ;
2010-12-30 22:57:43 +01:00
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( localTypeTok , " %type% < " ) ) {
2014-10-12 16:06:50 +02:00
if ( Token : : Match ( tok , " const_cast|dynamic_cast|reinterpret_cast|static_cast < " ) )
return false ;
2013-04-15 22:48:28 +02:00
const Token * closeTok = localTypeTok - > next ( ) - > link ( ) ;
if ( closeTok ) {
2011-01-18 10:51:57 +01:00
localVarTok = skipPointers ( closeTok - > next ( ) ) ;
2011-01-18 10:14:12 +01:00
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( localVarTok , " :: %type% %name% [;=({] " ) ) {
2013-03-30 13:49:56 +01:00
if ( localVarTok - > strAt ( 3 ) ! = " ( " | |
2014-08-05 15:33:57 +02:00
Token : : Match ( localVarTok - > linkAt ( 3 ) , " [)}] ; " ) ) {
2013-03-30 13:49:56 +01:00
localTypeTok = localVarTok - > next ( ) ;
localVarTok = localVarTok - > tokAt ( 2 ) ;
}
2011-01-02 00:36:22 +01:00
}
}
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( localTypeTok , " %type% " ) ) {
2020-11-16 20:11:26 +01:00
if ( isCPP11 & & Token : : simpleMatch ( localTypeTok , " decltype ( " ) & & Token : : Match ( localTypeTok - > linkAt ( 1 ) , " ) %name%|*|&|&& " ) )
localVarTok = skipPointersAndQualifiers ( localTypeTok - > linkAt ( 1 ) - > next ( ) ) ;
else {
localVarTok = skipPointersAndQualifiers ( localTypeTok - > next ( ) ) ;
if ( isCPP11 & & Token : : simpleMatch ( localVarTok , " decltype ( " ) & & Token : : Match ( localVarTok - > linkAt ( 1 ) , " ) %name%|*|&|&& " ) )
localVarTok = skipPointersAndQualifiers ( localVarTok - > linkAt ( 1 ) - > next ( ) ) ;
}
2011-01-18 10:51:57 +01:00
}
2010-12-30 22:57:43 +01:00
2015-10-26 19:20:42 +01:00
if ( ! localVarTok )
return false ;
2022-04-01 23:26:44 +02:00
while ( Token : : Match ( localVarTok , " const|*|& " ) )
2012-05-14 21:47:02 +02:00
localVarTok = localVarTok - > next ( ) ;
2016-02-03 22:49:57 +01:00
if ( Token : : Match ( localVarTok , " %name% ;|= " ) | | ( localVarTok & & localVarTok - > varId ( ) & & localVarTok - > strAt ( 1 ) = = " : " ) ) {
2011-02-27 16:21:14 +01:00
vartok = localVarTok ;
typetok = localTypeTok ;
2015-01-31 10:50:39 +01:00
} else if ( Token : : Match ( localVarTok , " %name% ) | [ " ) && localVarTok->str() != " operator " ) {
2011-01-18 10:51:57 +01:00
vartok = localVarTok ;
typetok = localTypeTok ;
2016-02-03 22:49:57 +01:00
} else if ( localVarTok & & localVarTok - > varId ( ) & & Token : : Match ( localVarTok , " %name% (| { " ) &&
2014-08-05 15:33:57 +02:00
Token : : Match ( localVarTok - > next ( ) - > link ( ) , " )|} ; " ) ) {
2011-07-23 21:12:30 +02:00
vartok = localVarTok ;
typetok = localTypeTok ;
2012-01-26 04:05:29 +01:00
} else if ( type = = eCatch & &
2015-01-31 10:50:39 +01:00
Token : : Match ( localVarTok , " %name% ) " ) ) {
2012-01-26 04:05:29 +01:00
vartok = localVarTok ;
typetok = localTypeTok ;
2011-07-23 21:12:30 +02:00
}
2012-01-26 04:05:29 +01:00
2014-02-16 10:32:10 +01:00
return nullptr ! = vartok ;
2010-12-30 09:46:44 +01:00
}
2016-04-22 06:02:54 +02:00
const Token * Scope : : addEnum ( const Token * tok , bool isCpp )
{
const Token * tok2 = tok - > next ( ) ;
// skip over class if present
if ( isCpp & & tok2 - > str ( ) = = " class " )
tok2 = tok2 - > next ( ) ;
// skip over name
tok2 = tok2 - > next ( ) ;
// save type if present
if ( tok2 - > str ( ) = = " : " ) {
tok2 = tok2 - > next ( ) ;
enumType = tok2 ;
tok2 = tok2 - > next ( ) ;
}
// add enumerators
if ( tok2 - > str ( ) = = " { " ) {
const Token * end = tok2 - > link ( ) ;
tok2 = tok2 - > next ( ) ;
while ( Token : : Match ( tok2 , " %name% =|,|} " ) | |
( Token : : Match ( tok2 , " %name% ( " ) & & Token : : Match ( tok2 - > linkAt ( 1 ) , " ) ,|} " ) ) ) {
Enumerator enumerator ( this ) ;
// save enumerator name
enumerator . name = tok2 ;
// skip over name
tok2 = tok2 - > next ( ) ;
if ( tok2 - > str ( ) = = " = " ) {
// skip over "="
tok2 = tok2 - > next ( ) ;
if ( tok2 - > str ( ) = = " } " )
return nullptr ;
enumerator . start = tok2 ;
while ( ! Token : : Match ( tok2 , " ,|} " ) ) {
if ( tok2 - > link ( ) )
tok2 = tok2 - > link ( ) ;
enumerator . end = tok2 ;
tok2 = tok2 - > next ( ) ;
}
} else if ( tok2 - > str ( ) = = " ( " ) {
// skip over unknown macro
tok2 = tok2 - > link ( ) - > next ( ) ;
}
if ( tok2 - > str ( ) = = " , " ) {
enumeratorList . push_back ( enumerator ) ;
tok2 = tok2 - > next ( ) ;
} else if ( tok2 - > str ( ) = = " } " ) {
enumeratorList . push_back ( enumerator ) ;
break ;
}
}
if ( tok2 = = end ) {
tok2 = tok2 - > next ( ) ;
2022-04-26 07:22:53 +02:00
if ( tok2 & & tok2 - > str ( ) ! = " ; " & & ( isCpp | | tok2 - > str ( ) ! = " ) " ) )
2016-04-22 06:02:54 +02:00
tok2 = nullptr ;
} else
tok2 = nullptr ;
} else
tok2 = nullptr ;
return tok2 ;
}
2022-06-08 16:58:57 +02:00
const Enumerator * SymbolDatabase : : findEnumerator ( const Token * tok , std : : set < std : : string > & tokensThatAreNotEnumeratorValues ) const
2016-04-22 06:02:54 +02:00
{
2022-06-10 20:40:37 +02:00
if ( tok - > isKeyword ( ) )
return nullptr ;
2016-04-22 06:02:54 +02:00
2022-06-10 20:40:37 +02:00
const std : : string & tokStr = tok - > str ( ) ;
2017-10-18 18:01:36 +02:00
2022-06-10 20:40:37 +02:00
if ( tokensThatAreNotEnumeratorValues . find ( tokStr ) ! = tokensThatAreNotEnumeratorValues . end ( ) )
2017-10-20 01:53:20 +02:00
return nullptr ;
2022-06-10 20:40:37 +02:00
const Scope * scope = tok - > scope ( ) ;
2017-10-18 18:01:36 +02:00
2016-04-22 06:02:54 +02:00
// check for qualified name
if ( tok - > strAt ( - 1 ) = = " :: " ) {
// find first scope
const Token * tok1 = tok ;
while ( Token : : Match ( tok1 - > tokAt ( - 2 ) , " %name% :: " ) )
tok1 = tok1 - > tokAt ( - 2 ) ;
if ( tok1 - > strAt ( - 1 ) = = " :: " )
scope = & scopeList . front ( ) ;
else {
// FIXME search base class here
// find first scope
while ( scope & & scope - > nestedIn ) {
const Scope * temp = scope - > nestedIn - > findRecordInNestedList ( tok1 - > str ( ) ) ;
if ( temp ) {
scope = temp ;
break ;
}
scope = scope - > nestedIn ;
}
}
if ( scope ) {
tok1 = tok1 - > tokAt ( 2 ) ;
while ( scope & & Token : : Match ( tok1 , " %name% :: " ) ) {
scope = scope - > findRecordInNestedList ( tok1 - > str ( ) ) ;
tok1 = tok1 - > tokAt ( 2 ) ;
}
if ( scope ) {
2017-10-18 18:01:36 +02:00
const Enumerator * enumerator = scope - > findEnumerator ( tokStr ) ;
2016-04-22 06:02:54 +02:00
if ( enumerator ) // enum class
return enumerator ;
// enum
else {
2022-06-08 16:58:57 +02:00
for ( std : : vector < Scope * > : : const_iterator it = scope - > nestedList . begin ( ) , end = scope - > nestedList . end ( ) ; it ! = end ; + + it ) {
2017-10-18 18:01:36 +02:00
enumerator = ( * it ) - > findEnumerator ( tokStr ) ;
2016-04-22 06:02:54 +02:00
2022-06-10 20:40:37 +02:00
if ( enumerator & & ! ( enumerator - > scope & & enumerator - > scope - > enumClass ) )
2016-04-22 06:02:54 +02:00
return enumerator ;
}
}
}
}
2022-06-10 20:40:37 +02:00
} else { // unqualified name
2017-10-18 18:01:36 +02:00
const Enumerator * enumerator = scope - > findEnumerator ( tokStr ) ;
2016-04-22 06:02:54 +02:00
2022-06-10 20:40:37 +02:00
if ( enumerator & & ! ( enumerator - > scope & & enumerator - > scope - > enumClass ) )
2016-04-22 06:02:54 +02:00
return enumerator ;
2022-06-08 16:58:57 +02:00
for ( std : : vector < Scope * > : : const_iterator s = scope - > nestedList . begin ( ) ; s ! = scope - > nestedList . end ( ) ; + + s ) {
2017-10-18 18:01:36 +02:00
enumerator = ( * s ) - > findEnumerator ( tokStr ) ;
2016-04-22 06:02:54 +02:00
2022-06-10 20:40:37 +02:00
if ( enumerator & & ! ( enumerator - > scope & & enumerator - > scope - > enumClass ) )
2016-04-22 06:02:54 +02:00
return enumerator ;
}
if ( scope - > definedType ) {
2017-08-28 17:19:03 +02:00
const std : : vector < Type : : BaseInfo > & derivedFrom = scope - > definedType - > derivedFrom ;
2019-09-19 20:29:33 +02:00
for ( const Type : : BaseInfo & i : derivedFrom ) {
const Type * derivedFromType = i . type ;
2021-08-07 20:51:18 +02:00
if ( derivedFromType & & derivedFromType - > classScope ) {
2017-10-18 18:01:36 +02:00
enumerator = derivedFromType - > classScope - > findEnumerator ( tokStr ) ;
2016-04-22 06:02:54 +02:00
2022-06-10 20:40:37 +02:00
if ( enumerator & & ! ( enumerator - > scope & & enumerator - > scope - > enumClass ) )
2016-04-22 06:02:54 +02:00
return enumerator ;
}
}
}
2011-01-02 00:36:22 +01:00
2017-08-02 08:17:29 +02:00
while ( scope - > nestedIn ) {
2016-05-09 13:08:00 +02:00
if ( scope - > type = = Scope : : eFunction & & scope - > functionOf )
2016-05-09 12:40:56 +02:00
scope = scope - > functionOf ;
else
scope = scope - > nestedIn ;
2017-10-18 18:01:36 +02:00
enumerator = scope - > findEnumerator ( tokStr ) ;
2016-05-09 12:40:56 +02:00
2022-06-10 20:40:37 +02:00
if ( enumerator & & ! ( enumerator - > scope & & enumerator - > scope - > enumClass ) )
2016-05-09 12:40:56 +02:00
return enumerator ;
2022-06-08 16:58:57 +02:00
for ( std : : vector < Scope * > : : const_iterator s = scope - > nestedList . begin ( ) ; s ! = scope - > nestedList . end ( ) ; + + s ) {
2017-10-18 18:01:36 +02:00
enumerator = ( * s ) - > findEnumerator ( tokStr ) ;
2016-05-09 12:40:56 +02:00
2022-06-10 20:40:37 +02:00
if ( enumerator & & ! ( enumerator - > scope & & enumerator - > scope - > enumClass ) )
2016-05-09 12:40:56 +02:00
return enumerator ;
}
}
2016-04-22 06:02:54 +02:00
}
2011-01-02 00:36:22 +01:00
2022-06-08 16:58:57 +02:00
tokensThatAreNotEnumeratorValues . insert ( tokStr ) ;
2017-10-18 18:01:36 +02:00
2016-04-22 06:02:54 +02:00
return nullptr ;
}
2015-01-02 21:38:19 +01:00
2010-12-02 07:35:01 +01:00
//---------------------------------------------------------------------------
2016-08-13 21:25:57 +02:00
const Type * SymbolDatabase : : findVariableTypeInBase ( const Scope * scope , const Token * typeTok ) const
{
if ( scope & & scope - > definedType & & ! scope - > definedType - > derivedFrom . empty ( ) ) {
2017-09-04 16:55:45 +02:00
const std : : vector < Type : : BaseInfo > & derivedFrom = scope - > definedType - > derivedFrom ;
2019-09-19 20:29:33 +02:00
for ( const Type : : BaseInfo & i : derivedFrom ) {
const Type * base = i . type ;
2016-08-13 21:25:57 +02:00
if ( base & & base - > classScope ) {
2021-01-18 19:01:04 +01:00
if ( base - > classScope = = scope )
return nullptr ;
2016-08-13 21:25:57 +02:00
const Type * type = base - > classScope - > findType ( typeTok - > str ( ) ) ;
if ( type )
return type ;
type = findVariableTypeInBase ( base - > classScope , typeTok ) ;
if ( type )
return type ;
}
}
}
2017-10-18 18:01:36 +02:00
2016-08-13 21:25:57 +02:00
return nullptr ;
}
//---------------------------------------------------------------------------
2013-03-05 13:33:38 +01:00
const Type * SymbolDatabase : : findVariableType ( const Scope * start , const Token * typeTok ) const
2010-12-02 07:35:01 +01:00
{
2016-08-13 21:25:57 +02:00
const Scope * scope = start ;
2016-04-22 06:02:54 +02:00
// check if type does not have a namespace
if ( typeTok - > strAt ( - 1 ) ! = " :: " & & typeTok - > strAt ( 1 ) ! = " :: " ) {
2018-05-27 10:53:34 +02:00
// check if type same as scope
if ( start - > isClassOrStruct ( ) & & typeTok - > str ( ) = = start - > className )
return start - > definedType ;
2016-08-13 21:25:57 +02:00
while ( scope ) {
2021-08-04 22:30:39 +02:00
// look for type in this scope
const Type * type = scope - > findType ( typeTok - > str ( ) ) ;
if ( type )
return type ;
2016-04-22 06:02:54 +02:00
2016-08-13 21:25:57 +02:00
// look for type in base classes if possible
if ( scope - > isClassOrStruct ( ) ) {
2021-08-04 22:30:39 +02:00
type = findVariableTypeInBase ( scope , typeTok ) ;
2016-08-13 21:25:57 +02:00
if ( type )
return type ;
2016-04-22 06:02:54 +02:00
}
2016-08-13 21:25:57 +02:00
// check if in member function class to see if it's present in class
if ( scope - > type = = Scope : : eFunction & & scope - > functionOf ) {
const Scope * scope1 = scope - > functionOf ;
2016-04-22 06:02:54 +02:00
2021-08-04 22:30:39 +02:00
type = scope1 - > findType ( typeTok - > str ( ) ) ;
2016-08-04 09:06:32 +02:00
2016-08-13 21:25:57 +02:00
if ( type )
return type ;
2016-08-04 09:06:32 +02:00
2016-08-13 21:25:57 +02:00
type = findVariableTypeInBase ( scope1 , typeTok ) ;
if ( type )
return type ;
}
scope = scope - > nestedIn ;
2016-08-04 09:06:32 +02:00
}
2016-04-22 06:02:54 +02:00
}
2016-08-13 21:25:57 +02:00
// check for a qualified name and use it when given
else if ( typeTok - > strAt ( - 1 ) = = " :: " ) {
// check if type is not part of qualification
if ( typeTok - > strAt ( 1 ) = = " :: " )
return nullptr ;
2010-12-02 07:35:01 +01:00
2016-08-13 21:25:57 +02:00
// find start of qualified function name
const Token * tok1 = typeTok ;
2010-12-02 07:35:01 +01:00
2018-05-01 07:32:19 +02:00
while ( Token : : Match ( tok1 - > tokAt ( - 2 ) , " %type% :: " ) | |
2018-05-06 08:23:07 +02:00
( Token : : simpleMatch ( tok1 - > tokAt ( - 2 ) , " > :: " ) & & tok1 - > linkAt ( - 2 ) & & Token : : Match ( tok1 - > linkAt ( - 2 ) - > tokAt ( - 1 ) , " %type% " ) ) ) {
2018-05-01 07:32:19 +02:00
if ( tok1 - > strAt ( - 1 ) = = " :: " )
tok1 = tok1 - > tokAt ( - 2 ) ;
else
tok1 = tok1 - > linkAt ( - 2 ) - > tokAt ( - 1 ) ;
}
2010-12-02 07:35:01 +01:00
2016-08-13 21:25:57 +02:00
// check for global scope
if ( tok1 - > strAt ( - 1 ) = = " :: " ) {
scope = & scopeList . front ( ) ;
2016-08-04 09:06:32 +02:00
2016-08-13 21:25:57 +02:00
scope = scope - > findRecordInNestedList ( tok1 - > str ( ) ) ;
}
2016-08-04 09:06:32 +02:00
2016-08-13 21:25:57 +02:00
// find start of qualification
else {
while ( scope ) {
if ( scope - > className = = tok1 - > str ( ) )
break ;
else {
const Scope * scope1 = scope - > findRecordInNestedList ( tok1 - > str ( ) ) ;
if ( scope1 ) {
scope = scope1 ;
break ;
2018-04-23 22:27:15 +02:00
} else if ( scope - > type = = Scope : : eFunction & & scope - > functionOf )
scope = scope - > functionOf ;
else
2016-08-13 21:25:57 +02:00
scope = scope - > nestedIn ;
}
2016-08-02 23:30:46 +02:00
}
2016-01-30 14:04:48 +01:00
}
2016-08-13 21:25:57 +02:00
if ( scope ) {
// follow qualification
2018-05-01 07:32:19 +02:00
while ( scope & & ( Token : : Match ( tok1 , " %type% :: " ) | |
2018-05-06 08:23:07 +02:00
( Token : : Match ( tok1 , " %type% < " ) & & Token : : simpleMatch ( tok1 - > linkAt ( 1 ) , " > :: " ) ) ) ) {
2018-05-01 07:32:19 +02:00
if ( tok1 - > strAt ( 1 ) = = " :: " )
tok1 = tok1 - > tokAt ( 2 ) ;
else
tok1 = tok1 - > linkAt ( 1 ) - > tokAt ( 2 ) ;
2016-08-13 21:25:57 +02:00
const Scope * temp = scope - > findRecordInNestedList ( tok1 - > str ( ) ) ;
if ( ! temp ) {
// look in base classes
const Type * type = findVariableTypeInBase ( scope , tok1 ) ;
if ( type )
return type ;
2016-01-30 14:04:48 +01:00
}
2016-08-13 21:25:57 +02:00
scope = temp ;
}
2016-01-30 14:04:48 +01:00
2016-08-13 21:25:57 +02:00
if ( scope & & scope - > definedType )
return scope - > definedType ;
2010-11-13 08:08:45 +01:00
}
}
2010-12-02 07:35:01 +01:00
2014-02-16 10:32:10 +01:00
return nullptr ;
2010-11-13 08:08:45 +01:00
}
2016-05-26 18:07:56 +02:00
bool Scope : : hasInlineOrLambdaFunction ( ) const
2016-05-26 17:42:27 +02:00
{
2019-07-22 12:24:16 +02:00
for ( const Scope * s : nestedList ) {
2016-05-26 17:42:27 +02:00
// Inline function
2018-04-27 22:36:30 +02:00
if ( s - > type = = Scope : : eUnconditional & & Token : : simpleMatch ( s - > bodyStart - > previous ( ) , " ) { " ) )
2016-05-26 17:42:27 +02:00
return true ;
2016-05-26 18:07:56 +02:00
// Lambda function
if ( s - > type = = Scope : : eLambda )
return true ;
2020-07-07 21:36:14 +02:00
if ( s - > hasInlineOrLambdaFunction ( ) )
return true ;
2016-05-26 17:42:27 +02:00
}
return false ;
}
2011-01-28 08:33:02 +01:00
2019-07-22 11:25:51 +02:00
void Scope : : findFunctionInBase ( const std : : string & name , nonneg int args , std : : vector < const Function * > & matches ) const
2014-11-17 16:04:44 +01:00
{
if ( isClassOrStruct ( ) & & definedType & & ! definedType - > derivedFrom . empty ( ) ) {
2017-09-04 16:55:45 +02:00
const std : : vector < Type : : BaseInfo > & derivedFrom = definedType - > derivedFrom ;
2019-09-19 20:29:33 +02:00
for ( const Type : : BaseInfo & i : derivedFrom ) {
const Type * base = i . type ;
2014-11-17 16:04:44 +01:00
if ( base & & base - > classScope ) {
if ( base - > classScope = = this ) // Ticket #5120, #5125: Recursive class; tok should have been found already
continue ;
2022-06-08 16:58:57 +02:00
auto range = base - > classScope - > functionMap . equal_range ( name ) ;
for ( std : : multimap < std : : string , const Function * > : : const_iterator it = range . first ; it ! = range . second ; + + it ) {
2015-01-02 21:38:19 +01:00
const Function * func = it - > second ;
2021-01-03 11:17:32 +01:00
if ( ( func - > isVariadic ( ) & & args > = ( func - > argCount ( ) - 1 ) ) | |
( args = = func - > argCount ( ) | | ( args < func - > argCount ( ) & & args > = func - > minArgCount ( ) ) ) ) {
2015-01-02 21:38:19 +01:00
matches . push_back ( func ) ;
2014-11-17 16:04:44 +01:00
}
}
2015-01-02 21:38:19 +01:00
base - > classScope - > findFunctionInBase ( name , args , matches ) ;
2014-11-17 16:04:44 +01:00
}
}
}
}
2021-01-18 19:01:04 +01:00
const Scope * Scope : : findRecordInBase ( const std : : string & name ) const
{
if ( isClassOrStruct ( ) & & definedType & & ! definedType - > derivedFrom . empty ( ) ) {
const std : : vector < Type : : BaseInfo > & derivedFrom = definedType - > derivedFrom ;
for ( const Type : : BaseInfo & i : derivedFrom ) {
const Type * base = i . type ;
if ( base & & base - > classScope ) {
if ( base - > classScope = = this ) // Recursive class; tok should have been found already
continue ;
if ( base - > name ( ) = = name ) {
return base - > classScope ;
}
2021-03-31 22:07:20 +02:00
const : : Type * t = base - > classScope - > findType ( name ) ;
if ( t )
return t - > classScope ;
2021-01-18 19:01:04 +01:00
}
}
}
return nullptr ;
}
2021-11-12 20:05:43 +01:00
std : : vector < const Scope * > Scope : : findAssociatedScopes ( ) const
{
std : : vector < const Scope * > result = { this } ;
if ( isClassOrStruct ( ) & & definedType & & ! definedType - > derivedFrom . empty ( ) ) {
const std : : vector < Type : : BaseInfo > & derivedFrom = definedType - > derivedFrom ;
for ( const Type : : BaseInfo & i : derivedFrom ) {
const Type * base = i . type ;
if ( base & & base - > classScope ) {
if ( contains ( result , base - > classScope ) )
continue ;
std : : vector < const Scope * > baseScopes = base - > classScope - > findAssociatedScopes ( ) ;
result . insert ( result . end ( ) , baseScopes . begin ( ) , baseScopes . end ( ) ) ;
}
}
}
return result ;
}
2014-11-17 16:04:44 +01:00
//---------------------------------------------------------------------------
2017-03-15 18:36:59 +01:00
static void checkVariableCallMatch ( const Variable * callarg , const Variable * funcarg , size_t & same , size_t & fallback1 , size_t & fallback2 )
{
if ( callarg ) {
2022-10-02 07:12:40 +02:00
const ValueType : : MatchResult res = ValueType : : matchParameter ( callarg - > valueType ( ) , callarg , funcarg ) ;
2019-07-29 18:14:06 +02:00
if ( res = = ValueType : : MatchResult : : SAME ) {
same + + ;
return ;
}
2019-07-31 18:24:15 +02:00
if ( res = = ValueType : : MatchResult : : FALLBACK1 ) {
fallback1 + + ;
return ;
}
2019-07-31 18:25:47 +02:00
if ( res = = ValueType : : MatchResult : : FALLBACK2 ) {
fallback2 + + ;
return ;
}
2019-08-03 10:10:22 +02:00
if ( res = = ValueType : : MatchResult : : NOMATCH )
return ;
2019-07-29 18:14:06 +02:00
2022-10-02 07:12:40 +02:00
const bool ptrequals = callarg - > isArrayOrPointer ( ) = = funcarg - > isArrayOrPointer ( ) ;
const bool constEquals = ! callarg - > isArrayOrPointer ( ) | | ( ( callarg - > typeStartToken ( ) - > strAt ( - 1 ) = = " const " ) = = ( funcarg - > typeStartToken ( ) - > strAt ( - 1 ) = = " const " ) ) ;
2017-03-15 18:36:59 +01:00
if ( ptrequals & & constEquals & &
callarg - > typeStartToken ( ) - > str ( ) = = funcarg - > typeStartToken ( ) - > str ( ) & &
callarg - > typeStartToken ( ) - > isUnsigned ( ) = = funcarg - > typeStartToken ( ) - > isUnsigned ( ) & &
callarg - > typeStartToken ( ) - > isLong ( ) = = funcarg - > typeStartToken ( ) - > isLong ( ) ) {
same + + ;
} else if ( callarg - > isArrayOrPointer ( ) ) {
if ( ptrequals & & constEquals & & funcarg - > typeStartToken ( ) - > str ( ) = = " void " )
fallback1 + + ;
else if ( constEquals & & funcarg - > isStlStringType ( ) & & Token : : Match ( callarg - > typeStartToken ( ) , " char|wchar_t " ) )
fallback2 + + ;
} else if ( ptrequals ) {
2018-04-04 21:51:31 +02:00
const bool takesInt = Token : : Match ( funcarg - > typeStartToken ( ) , " char|short|int|long " ) ;
const bool takesFloat = Token : : Match ( funcarg - > typeStartToken ( ) , " float|double " ) ;
const bool passesInt = Token : : Match ( callarg - > typeStartToken ( ) , " char|short|int|long " ) ;
const bool passesFloat = Token : : Match ( callarg - > typeStartToken ( ) , " float|double " ) ;
2017-03-15 18:36:59 +01:00
if ( ( takesInt & & passesInt ) | | ( takesFloat & & passesFloat ) )
fallback1 + + ;
else if ( ( takesInt & & passesFloat ) | | ( takesFloat & & passesInt ) )
fallback2 + + ;
}
}
}
2019-08-03 10:10:22 +02:00
static std : : string getTypeString ( const Token * typeToken )
{
if ( ! typeToken )
return " " ;
while ( Token : : Match ( typeToken , " %name%|*|&|:: " ) ) {
if ( typeToken - > str ( ) = = " :: " ) {
std : : string ret ;
while ( Token : : Match ( typeToken , " :: %name% " ) ) {
ret + = " :: " + typeToken - > strAt ( 1 ) ;
typeToken = typeToken - > tokAt ( 2 ) ;
2021-04-09 07:44:20 +02:00
if ( typeToken - > str ( ) = = " < " ) {
for ( const Token * tok = typeToken ; tok ! = typeToken - > link ( ) ; tok = tok - > next ( ) )
ret + = tok - > str ( ) ;
ret + = " > " ;
typeToken = typeToken - > link ( ) - > next ( ) ;
}
2019-08-03 10:10:22 +02:00
}
return ret ;
}
if ( Token : : Match ( typeToken , " %name% const| %var%|*|& " ) ) {
return typeToken - > str ( ) ;
}
typeToken = typeToken - > next ( ) ;
}
return " " ;
}
2015-05-23 11:56:11 +02:00
const Function * Scope : : findFunction ( const Token * tok , bool requireConst ) const
2013-01-01 09:53:40 +01:00
{
2020-09-23 22:10:47 +02:00
const bool isCall = Token : : Match ( tok - > next ( ) , " (|{ " ) ;
2014-11-17 16:04:44 +01:00
2019-07-29 21:17:15 +02:00
const std : : vector < const Token * > arguments = getArguments ( tok ) ;
2014-11-17 16:04:44 +01:00
std : : vector < const Function * > matches ;
// find all the possible functions that could match
const std : : size_t args = arguments . size ( ) ;
2019-10-01 19:09:34 +02:00
auto addMatchingFunctions = [ & ] ( const Scope * scope ) {
2022-06-08 16:58:57 +02:00
auto range = scope - > functionMap . equal_range ( tok - > str ( ) ) ;
for ( std : : multimap < std : : string , const Function * > : : const_iterator it = range . first ; it ! = range . second ; + + it ) {
2019-10-01 19:09:34 +02:00
const Function * func = it - > second ;
2020-09-23 22:10:47 +02:00
if ( ! isCall | | args = = func - > argCount ( ) | |
2022-02-10 11:17:06 +01:00
( func - > isVariadic ( ) & & args > = ( func - > minArgCount ( ) - 1 ) ) | |
2019-10-01 19:09:34 +02:00
( args < func - > argCount ( ) & & args > = func - > minArgCount ( ) ) ) {
matches . push_back ( func ) ;
}
2014-11-17 16:04:44 +01:00
}
2019-10-01 19:09:34 +02:00
} ;
addMatchingFunctions ( this ) ;
// check in anonumous namespaces
for ( const Scope * nestedScope : nestedList ) {
if ( nestedScope - > type = = eNamespace & & nestedScope - > className . empty ( ) )
addMatchingFunctions ( nestedScope ) ;
2014-11-17 16:04:44 +01:00
}
// check in base classes
2015-01-02 21:38:19 +01:00
findFunctionInBase ( tok - > str ( ) , args , matches ) ;
2014-11-17 16:04:44 +01:00
2020-09-23 22:10:47 +02:00
// Non-call => Do not match parameters
if ( ! isCall ) {
return matches . empty ( ) ? nullptr : matches [ 0 ] ;
}
2017-02-25 23:11:42 +01:00
const Function * fallback1Func = nullptr ;
const Function * fallback2Func = nullptr ;
2014-11-17 16:04:44 +01:00
// check each function against the arguments in the function call for a match
2014-11-20 06:18:29 +01:00
for ( std : : size_t i = 0 ; i < matches . size ( ) ; ) {
2017-04-01 10:18:53 +02:00
bool constFallback = false ;
2014-11-17 16:04:44 +01:00
const Function * func = matches [ i ] ;
size_t same = 0 ;
2017-02-25 23:11:42 +01:00
2019-05-30 21:25:14 +02:00
if ( requireConst & & ! func - > isConst ( ) ) {
i + + ;
2019-05-30 20:26:45 +02:00
continue ;
2019-05-30 21:25:14 +02:00
}
2019-05-30 20:26:45 +02:00
2017-02-28 22:08:18 +01:00
if ( ! requireConst | | ! func - > isConst ( ) ) {
2017-02-25 23:11:42 +01:00
// get the function this call is in
const Scope * scope = tok - > scope ( ) ;
// check if this function is a member function
2017-08-01 13:26:35 +02:00
if ( scope & & scope - > functionOf & & scope - > functionOf - > isClassOrStruct ( ) & & scope - > function ) {
2017-02-25 23:11:42 +01:00
// check if isConst mismatches
2017-08-01 13:26:35 +02:00
if ( scope - > function - > isConst ( ) ! = func - > isConst ( ) ) {
2017-04-01 10:18:53 +02:00
if ( scope - > function - > isConst ( ) ) {
2017-11-03 10:39:57 +01:00
+ + i ;
2017-04-01 10:18:53 +02:00
continue ;
}
constFallback = true ;
2017-02-25 23:11:42 +01:00
}
}
}
size_t fallback1 = 0 ;
size_t fallback2 = 0 ;
2017-11-03 10:39:57 +01:00
bool erased = false ;
2014-11-17 16:04:44 +01:00
for ( std : : size_t j = 0 ; j < args ; + + j ) {
2017-02-25 23:11:42 +01:00
2016-08-02 08:58:11 +02:00
// don't check variadic arguments
if ( func - > isVariadic ( ) & & j > ( func - > argCount ( ) - 1 ) ) {
break ;
}
2014-11-17 16:04:44 +01:00
const Variable * funcarg = func - > getArgumentVar ( j ) ;
2019-08-01 17:53:14 +02:00
if ( ! arguments [ j ] - > valueType ( ) ) {
const Token * vartok = arguments [ j ] ;
int pointer = 0 ;
while ( vartok & & ( vartok - > isUnaryOp ( " & " ) | | vartok - > isUnaryOp ( " * " ) ) ) {
pointer + = vartok - > isUnaryOp ( " & " ) ? 1 : - 1 ;
vartok = vartok - > astOperand1 ( ) ;
2018-04-06 07:53:05 +02:00
}
2019-08-01 17:53:14 +02:00
if ( vartok & & vartok - > variable ( ) ) {
const Token * callArgTypeToken = vartok - > variable ( ) - > typeStartToken ( ) ;
2019-08-01 13:25:03 +02:00
const Token * funcArgTypeToken = funcarg - > typeStartToken ( ) ;
auto parseDecl = [ ] ( const Token * typeToken ) - > ValueType {
ValueType ret ;
while ( Token : : Match ( typeToken - > previous ( ) , " %name% " ) )
typeToken = typeToken - > previous ( ) ;
2019-08-03 10:10:22 +02:00
while ( Token : : Match ( typeToken , " %name%|*|&|::|< " ) )
2019-08-01 13:25:03 +02:00
{
if ( typeToken - > str ( ) = = " const " )
ret . constness | = ( 1 < < ret . pointer ) ;
else if ( typeToken - > str ( ) = = " * " )
ret . pointer + + ;
2019-08-03 10:10:22 +02:00
else if ( typeToken - > str ( ) = = " < " ) {
if ( ! typeToken - > link ( ) )
break ;
typeToken = typeToken - > link ( ) ;
}
2019-08-01 13:25:03 +02:00
typeToken = typeToken - > next ( ) ;
2019-07-31 12:38:36 +02:00
}
2019-08-01 13:25:03 +02:00
return ret ;
} ;
2019-08-03 10:10:22 +02:00
const std : : string type1 = getTypeString ( callArgTypeToken ) ;
const std : : string type2 = getTypeString ( funcArgTypeToken ) ;
if ( ! type1 . empty ( ) & & type1 = = type2 ) {
ValueType callArgType = parseDecl ( callArgTypeToken ) ;
callArgType . pointer + = pointer ;
ValueType funcArgType = parseDecl ( funcArgTypeToken ) ;
2019-08-01 13:25:03 +02:00
callArgType . sign = funcArgType . sign = ValueType : : Sign : : SIGNED ;
callArgType . type = funcArgType . type = ValueType : : Type : : INT ;
2019-08-03 10:10:22 +02:00
2022-10-02 07:12:40 +02:00
const ValueType : : MatchResult res = ValueType : : matchParameter ( & callArgType , & funcArgType ) ;
2019-08-01 13:25:03 +02:00
if ( res = = ValueType : : MatchResult : : SAME )
+ + same ;
else if ( res = = ValueType : : MatchResult : : FALLBACK1 )
+ + fallback1 ;
else if ( res = = ValueType : : MatchResult : : FALLBACK2 )
+ + fallback2 ;
2019-08-01 17:53:14 +02:00
continue ;
2016-08-02 23:34:11 +02:00
}
}
}
2019-08-01 17:53:14 +02:00
// check for a match with a variable
if ( Token : : Match ( arguments [ j ] , " %var% ,|) " ) ) {
2019-08-02 15:41:00 +02:00
const Variable * callarg = arguments [ j ] - > variable ( ) ;
2019-08-01 17:53:14 +02:00
checkVariableCallMatch ( callarg , funcarg , same , fallback1 , fallback2 ) ;
}
2019-08-01 16:14:00 +02:00
else if ( funcarg - > isStlStringType ( ) & & arguments [ j ] - > valueType ( ) & & arguments [ j ] - > valueType ( ) - > pointer = = 1 & & arguments [ j ] - > valueType ( ) - > type = = ValueType : : Type : : CHAR )
2019-08-01 17:53:14 +02:00
fallback2 + + ;
2016-08-02 08:58:11 +02:00
2017-02-28 22:43:47 +01:00
// check for a match with nullptr
2019-08-01 17:29:25 +02:00
else if ( funcarg - > isPointer ( ) & & Token : : Match ( arguments [ j ] , " nullptr|NULL ,|) " ) )
2017-02-28 22:43:47 +01:00
same + + ;
2019-08-01 17:29:25 +02:00
2020-02-09 11:16:08 +01:00
else if ( funcarg - > isPointer ( ) & & MathLib : : isNullValue ( arguments [ j ] - > str ( ) ) )
2019-08-01 17:29:25 +02:00
fallback1 + + ;
2017-02-28 22:43:47 +01:00
2017-03-15 18:36:59 +01:00
// Try to evaluate the apparently more complex expression
2020-11-04 07:17:17 +01:00
else if ( check - > isCPP ( ) ) {
2019-08-03 10:10:22 +02:00
const Token * vartok = arguments [ j ] ;
2022-01-28 15:05:13 +01:00
if ( vartok - > str ( ) = = " . " ) {
const Token * rml = nextAfterAstRightmostLeaf ( vartok ) ;
if ( rml )
vartok = rml - > previous ( ) ;
}
2019-08-03 10:10:22 +02:00
while ( vartok - > isUnaryOp ( " & " ) | | vartok - > isUnaryOp ( " * " ) )
vartok = vartok - > astOperand1 ( ) ;
2022-01-24 21:52:00 +01:00
const Variable * var = vartok - > variable ( ) ;
// smart pointer deref?
2022-02-16 07:02:26 +01:00
bool unknownDeref = false ;
if ( var & & vartok - > astParent ( ) & & vartok - > astParent ( ) - > str ( ) = = " * " ) {
if ( var - > isSmartPointer ( ) & & var - > valueType ( ) & & var - > valueType ( ) - > smartPointerTypeToken )
var = var - > valueType ( ) - > smartPointerTypeToken - > variable ( ) ;
else
unknownDeref = true ;
}
2022-10-02 07:12:40 +02:00
const ValueType : : MatchResult res = ValueType : : matchParameter ( arguments [ j ] - > valueType ( ) , var , funcarg ) ;
2019-07-31 18:35:56 +02:00
if ( res = = ValueType : : MatchResult : : SAME )
+ + same ;
else if ( res = = ValueType : : MatchResult : : FALLBACK1 )
+ + fallback1 ;
else if ( res = = ValueType : : MatchResult : : FALLBACK2 )
+ + fallback2 ;
2019-08-01 14:30:00 +02:00
else if ( res = = ValueType : : MatchResult : : NOMATCH ) {
2022-02-16 07:02:26 +01:00
if ( unknownDeref )
continue ;
2019-08-01 14:30:00 +02:00
// can't match so remove this function from possible matches
matches . erase ( matches . begin ( ) + i ) ;
erased = true ;
break ;
}
2017-03-15 18:36:59 +01:00
}
2020-11-04 07:17:17 +01:00
else
// C code: if number of arguments match then do not match types
fallback1 + + ;
2013-01-01 09:53:40 +01:00
}
2018-04-04 21:51:31 +02:00
const size_t hasToBe = func - > isVariadic ( ) ? ( func - > argCount ( ) - 1 ) : args ;
2017-02-28 22:43:47 +01:00
2014-11-17 16:04:44 +01:00
// check if all arguments matched
2017-04-01 10:18:53 +02:00
if ( same = = hasToBe ) {
2019-05-30 19:24:27 +02:00
if ( constFallback | | ( ! requireConst & & func - > isConst ( ) ) )
2017-04-01 10:18:53 +02:00
fallback1Func = func ;
else
return func ;
}
2015-05-23 11:56:11 +02:00
2017-04-01 10:18:53 +02:00
else if ( ! fallback1Func ) {
2017-02-28 22:43:47 +01:00
if ( same + fallback1 = = hasToBe )
2017-02-25 23:11:42 +01:00
fallback1Func = func ;
2017-02-28 22:43:47 +01:00
else if ( ! fallback2Func & & same + fallback2 + fallback1 = = hasToBe )
2017-02-25 23:11:42 +01:00
fallback2Func = func ;
2014-11-01 14:36:17 +01:00
}
2014-11-20 06:18:29 +01:00
if ( ! erased )
+ + i ;
2014-11-01 14:36:17 +01:00
}
2017-02-25 23:11:42 +01:00
// Fallback cases
if ( fallback1Func )
return fallback1Func ;
if ( fallback2Func )
return fallback2Func ;
2022-02-27 19:15:19 +01:00
// remove pure virtual function
matches . erase ( std : : remove_if ( matches . begin ( ) , matches . end ( ) , [ ] ( const Function * m ) {
return m - > isPure ( ) ;
} ) , matches . end ( ) ) ;
2017-02-25 23:11:42 +01:00
// Only one candidate left
2017-02-24 20:56:47 +01:00
if ( matches . size ( ) = = 1 )
2014-11-17 16:04:44 +01:00
return matches [ 0 ] ;
2014-10-30 13:47:20 +01:00
return nullptr ;
2013-01-01 09:53:40 +01:00
}
//---------------------------------------------------------------------------
2013-01-28 06:47:48 +01:00
const Function * SymbolDatabase : : findFunction ( const Token * tok ) const
2012-10-14 17:30:37 +02:00
{
2013-01-22 06:55:25 +01:00
// find the scope this function is in
2013-01-28 06:47:48 +01:00
const Scope * currScope = tok - > scope ( ) ;
2012-10-14 17:30:37 +02:00
while ( currScope & & currScope - > isExecutable ( ) ) {
if ( currScope - > functionOf )
currScope = currScope - > functionOf ;
else
currScope = currScope - > nestedIn ;
}
2013-01-22 06:55:25 +01:00
// check for a qualified name and use it when given
if ( tok - > strAt ( - 1 ) = = " :: " ) {
// find start of qualified function name
const Token * tok1 = tok ;
2018-05-01 07:32:19 +02:00
while ( Token : : Match ( tok1 - > tokAt ( - 2 ) , " >|%type% :: " ) ) {
if ( tok1 - > strAt ( - 2 ) = = " > " ) {
if ( tok1 - > linkAt ( - 2 ) )
tok1 = tok1 - > linkAt ( - 2 ) - > tokAt ( - 1 ) ;
else {
2018-06-16 16:10:28 +02:00
if ( mSettings - > debugwarnings )
2020-12-31 19:24:16 +01:00
debugMessage ( tok1 - > tokAt ( - 2 ) , " debug " , " SymbolDatabase::findFunction found '>' without link. " ) ;
2018-05-01 07:32:19 +02:00
return nullptr ;
}
} else
tok1 = tok1 - > tokAt ( - 2 ) ;
}
2013-01-22 06:55:25 +01:00
// check for global scope
if ( tok1 - > strAt ( - 1 ) = = " :: " ) {
currScope = & scopeList . front ( ) ;
2019-10-15 12:39:02 +02:00
if ( Token : : Match ( tok1 , " %name% ( " ) )
return currScope - > findFunction ( tok ) ;
2013-01-22 06:55:25 +01:00
currScope = currScope - > findRecordInNestedList ( tok1 - > str ( ) ) ;
}
// find start of qualification
else {
while ( currScope ) {
if ( currScope - > className = = tok1 - > str ( ) )
break ;
else {
const Scope * scope = currScope - > findRecordInNestedList ( tok1 - > str ( ) ) ;
if ( scope ) {
currScope = scope ;
break ;
} else
currScope = currScope - > nestedIn ;
}
}
}
if ( currScope ) {
2021-01-30 06:33:09 +01:00
while ( currScope & & tok1 & & ! ( Token : : Match ( tok1 , " %type% :: %name% [(),>] " ) | |
( Token : : Match ( tok1 , " %type% < " ) & & Token : : Match ( tok1 - > linkAt ( 1 ) , " > :: %name% ( " ) ) ) ) {
2018-05-01 07:32:19 +02:00
if ( tok1 - > strAt ( 1 ) = = " :: " )
tok1 = tok1 - > tokAt ( 2 ) ;
2021-01-30 06:33:09 +01:00
else if ( tok1 - > strAt ( 1 ) = = " < " )
2018-05-01 07:32:19 +02:00
tok1 = tok1 - > linkAt ( 1 ) - > tokAt ( 2 ) ;
2021-01-30 06:33:09 +01:00
else
tok1 = nullptr ;
2022-03-14 19:15:48 +01:00
if ( tok1 ) {
const Function * func = currScope - > findFunction ( tok1 ) ;
if ( func )
return func ;
2021-01-30 06:33:09 +01:00
currScope = currScope - > findRecordInNestedList ( tok1 - > str ( ) ) ;
2022-03-14 19:15:48 +01:00
}
2013-01-22 06:55:25 +01:00
}
2021-01-30 06:33:09 +01:00
if ( tok1 )
tok1 = tok1 - > tokAt ( 2 ) ;
2013-01-22 06:55:25 +01:00
if ( currScope & & tok1 )
2013-01-28 06:47:48 +01:00
return currScope - > findFunction ( tok1 ) ;
2013-01-22 06:55:25 +01:00
}
}
2013-01-23 16:53:55 +01:00
// check for member function
2013-07-08 06:38:33 +02:00
else if ( Token : : Match ( tok - > tokAt ( - 2 ) , " !!this . " ) ) {
2021-11-28 15:25:21 +01:00
const Token * tok1 = tok - > previous ( ) - > astOperand1 ( ) ;
if ( tok1 & & tok1 - > valueType ( ) & & tok1 - > valueType ( ) - > typeScope ) {
return tok1 - > valueType ( ) - > typeScope - > findFunction ( tok , tok1 - > valueType ( ) - > constness = = 1 ) ;
2021-12-04 17:00:55 +01:00
} else if ( tok1 & & Token : : Match ( tok1 - > previous ( ) , " %name% ( " ) & & tok1 - > previous ( ) - > function ( ) & &
tok1 - > previous ( ) - > function ( ) - > retDef ) {
2022-08-21 17:11:22 +02:00
ValueType vt = ValueType : : parseDecl ( tok1 - > previous ( ) - > function ( ) - > retDef , mSettings , mIsCpp ) ;
2021-12-04 17:00:55 +01:00
if ( vt . typeScope )
return vt . typeScope - > findFunction ( tok , vt . constness = = 1 ) ;
2021-11-28 15:25:21 +01:00
} else if ( Token : : Match ( tok1 , " %var% . " ) ) {
2015-01-31 10:50:39 +01:00
const Variable * var = getVariableFromVarId ( tok1 - > varId ( ) ) ;
if ( var & & var - > typeScope ( ) )
2019-05-30 20:26:45 +02:00
return var - > typeScope ( ) - > findFunction ( tok , var - > valueType ( ) - > constness = = 1 ) ;
2019-07-08 17:43:45 +02:00
if ( var & & var - > smartPointerType ( ) & & var - > smartPointerType ( ) - > classScope & & tok1 - > next ( ) - > originalName ( ) = = " -> " )
return var - > smartPointerType ( ) - > classScope - > findFunction ( tok , var - > valueType ( ) - > constness = = 1 ) ;
2019-05-30 20:26:45 +02:00
} else if ( Token : : simpleMatch ( tok - > previous ( ) - > astOperand1 ( ) , " ( " ) ) {
const Token * castTok = tok - > previous ( ) - > astOperand1 ( ) ;
if ( castTok - > isCast ( ) ) {
2022-08-21 17:11:22 +02:00
ValueType vt = ValueType : : parseDecl ( castTok - > next ( ) , mSettings , mIsCpp ) ;
2019-05-30 20:26:45 +02:00
if ( vt . typeScope )
return vt . typeScope - > findFunction ( tok , vt . constness = = 1 ) ;
}
2013-01-23 16:53:55 +01:00
}
}
2013-01-22 06:55:25 +01:00
// check in enclosing scopes
else {
while ( currScope ) {
2013-01-28 06:47:48 +01:00
const Function * func = currScope - > findFunction ( tok ) ;
2013-01-22 06:55:25 +01:00
if ( func )
return func ;
currScope = currScope - > nestedIn ;
}
2012-10-14 17:30:37 +02:00
}
2022-01-02 08:12:08 +01:00
// Check for constructor
2021-11-28 15:25:21 +01:00
if ( Token : : Match ( tok , " %name% (|{ " ) ) {
2022-08-21 17:11:22 +02:00
ValueType vt = ValueType : : parseDecl ( tok , mSettings , mIsCpp ) ;
2021-11-28 15:25:21 +01:00
if ( vt . typeScope )
return vt . typeScope - > findFunction ( tok , false ) ;
}
2017-08-09 20:00:26 +02:00
return nullptr ;
2012-10-14 17:30:37 +02:00
}
2011-01-28 08:33:02 +01:00
//---------------------------------------------------------------------------
2010-11-13 08:08:45 +01:00
2013-01-03 22:37:19 +01:00
const Scope * SymbolDatabase : : findScopeByName ( const std : : string & name ) const
2012-02-24 20:45:56 +01:00
{
2022-10-16 13:46:26 +02:00
auto it = std : : find_if ( scopeList . begin ( ) , scopeList . end ( ) , [ & ] ( const Scope & s ) {
return s . className = = name ;
} ) ;
return it = = scopeList . end ( ) ? nullptr : & * it ;
2012-02-24 20:45:56 +01:00
}
//---------------------------------------------------------------------------
2022-03-12 06:16:29 +01:00
const Scope * Scope : : findRecordInNestedList ( const std : : string & name , bool isC ) const
2012-11-30 06:03:58 +01:00
{
2021-08-01 21:51:37 +02:00
for ( const Scope * scope : nestedList ) {
if ( scope - > className = = name & & scope - > type ! = eFunction )
return scope ;
2022-03-12 06:16:29 +01:00
if ( isC ) {
const Scope * nestedScope = scope - > findRecordInNestedList ( name , isC ) ;
if ( nestedScope )
return nestedScope ;
}
2012-11-30 06:03:58 +01:00
}
2018-04-24 22:43:47 +02:00
const Type * nested_type = findType ( name ) ;
2019-01-31 16:53:51 +01:00
if ( nested_type ) {
if ( nested_type - > isTypeAlias ( ) ) {
if ( nested_type - > typeStart = = nested_type - > typeEnd )
return findRecordInNestedList ( nested_type - > typeStart - > str ( ) ) ;
} else
return nested_type - > classScope ;
}
2018-04-24 22:43:47 +02:00
2017-08-09 20:00:26 +02:00
return nullptr ;
2012-11-30 06:03:58 +01:00
}
//---------------------------------------------------------------------------
2013-03-05 13:33:38 +01:00
const Type * Scope : : findType ( const std : : string & name ) const
{
2017-10-15 02:53:41 +02:00
auto it = definedTypesMap . find ( name ) ;
2013-03-05 13:33:38 +01:00
2018-04-26 17:55:04 +02:00
// Type was found
if ( definedTypesMap . end ( ) ! = it )
2017-10-17 10:59:23 +02:00
return ( * it ) . second ;
2018-04-26 17:55:04 +02:00
// is type defined in anonymous namespace..
2022-07-10 10:57:29 +02:00
it = definedTypesMap . find ( emptyString ) ;
2018-04-26 17:55:04 +02:00
if ( it ! = definedTypesMap . end ( ) ) {
for ( const Scope * scope : nestedList ) {
if ( scope - > className . empty ( ) & & ( scope - > type = = eNamespace | | scope - > isClassOrStructOrUnion ( ) ) ) {
const Type * t = scope - > findType ( name ) ;
if ( t )
return t ;
}
}
2013-03-05 13:33:38 +01:00
}
2018-04-26 17:55:04 +02:00
// Type was not found
return nullptr ;
2013-03-05 13:33:38 +01:00
}
//---------------------------------------------------------------------------
2013-01-03 22:37:19 +01:00
Scope * Scope : : findInNestedListRecursive ( const std : : string & name )
2011-02-03 07:57:10 +01:00
{
2022-10-16 13:46:26 +02:00
auto it = std : : find_if ( nestedList . begin ( ) , nestedList . end ( ) , [ & ] ( const Scope * s ) {
return s - > className = = name ;
} ) ;
if ( it ! = nestedList . end ( ) )
return * it ;
2011-02-03 07:57:10 +01:00
2021-08-01 21:51:37 +02:00
for ( Scope * scope : nestedList ) {
Scope * child = scope - > findInNestedListRecursive ( name ) ;
2011-02-19 19:40:02 +01:00
if ( child )
return child ;
2011-02-03 07:57:10 +01:00
}
2017-08-09 20:00:26 +02:00
return nullptr ;
2011-02-03 07:57:10 +01:00
}
//---------------------------------------------------------------------------
2011-01-17 18:29:19 +01:00
const Function * Scope : : getDestructor ( ) const
2010-11-13 08:08:45 +01:00
{
2022-10-16 13:46:26 +02:00
auto it = std : : find_if ( functionList . begin ( ) , functionList . end ( ) , [ ] ( const Function & f ) {
return f . type = = Function : : eDestructor ;
} ) ;
return it = = functionList . end ( ) ? nullptr : & * it ;
2010-11-13 08:08:45 +01:00
}
//---------------------------------------------------------------------------
2012-11-26 16:34:44 +01:00
bool SymbolDatabase : : isCPP ( ) const
{
2018-06-16 16:10:28 +02:00
return mTokenizer - > isCPP ( ) ;
2012-11-26 16:34:44 +01:00
}
2012-11-30 06:03:58 +01:00
//---------------------------------------------------------------------------
2013-01-03 22:37:19 +01:00
const Scope * SymbolDatabase : : findScope ( const Token * tok , const Scope * startScope ) const
2012-11-30 06:03:58 +01:00
{
2014-02-16 11:47:52 +01:00
const Scope * scope = nullptr ;
2012-11-30 06:03:58 +01:00
// absolute path
if ( tok - > str ( ) = = " :: " ) {
tok = tok - > next ( ) ;
2013-03-05 13:33:38 +01:00
scope = & scopeList . front ( ) ;
}
// relative path
else if ( tok - > isName ( ) ) {
scope = startScope ;
}
2012-11-30 06:03:58 +01:00
2013-03-05 13:33:38 +01:00
while ( scope & & tok & & tok - > isName ( ) ) {
if ( tok - > strAt ( 1 ) = = " :: " ) {
2012-11-30 06:03:58 +01:00
scope = scope - > findRecordInNestedList ( tok - > str ( ) ) ;
2013-03-05 13:33:38 +01:00
tok = tok - > tokAt ( 2 ) ;
2018-05-06 08:23:07 +02:00
} else if ( tok - > strAt ( 1 ) = = " < " & & Token : : simpleMatch ( tok - > linkAt ( 1 ) , " > :: " ) ) {
2018-05-01 07:32:19 +02:00
scope = scope - > findRecordInNestedList ( tok - > str ( ) ) ;
tok = tok - > linkAt ( 1 ) - > tokAt ( 2 ) ;
2013-03-05 13:33:38 +01:00
} else
return scope - > findRecordInNestedList ( tok - > str ( ) ) ;
}
2012-11-30 06:03:58 +01:00
2013-03-05 13:33:38 +01:00
// not a valid path
2017-08-09 20:00:26 +02:00
return nullptr ;
2013-03-05 13:33:38 +01:00
}
2012-11-30 06:03:58 +01:00
2013-08-12 06:21:03 +02:00
//---------------------------------------------------------------------------
2022-02-12 08:19:07 +01:00
const Type * SymbolDatabase : : findType ( const Token * startTok , const Scope * startScope , bool lookOutside ) const
2013-03-05 13:33:38 +01:00
{
2013-08-12 06:21:03 +02:00
// skip over struct or union
if ( Token : : Match ( startTok , " struct|union " ) )
startTok = startTok - > next ( ) ;
// type same as scope
2016-08-21 16:11:23 +02:00
if ( startTok - > str ( ) = = startScope - > className & & startScope - > isClassOrStruct ( ) & & startTok - > strAt ( 1 ) ! = " :: " )
2013-08-12 06:21:03 +02:00
return startScope - > definedType ;
2022-03-12 06:16:29 +01:00
if ( mTokenizer - > isC ( ) ) {
const Scope * scope = startScope ;
while ( scope ) {
if ( startTok - > str ( ) = = scope - > className & & scope - > isClassOrStruct ( ) )
return scope - > definedType ;
const Scope * typeScope = scope - > findRecordInNestedList ( startTok - > str ( ) , /*isC*/ true ) ;
if ( typeScope ) {
if ( startTok - > str ( ) = = typeScope - > className & & typeScope - > isClassOrStruct ( ) ) {
if ( const Type * type = typeScope - > definedType )
return type ;
}
}
scope = scope - > nestedIn ;
}
return nullptr ;
}
2017-07-16 01:14:15 +02:00
const Scope * start_scope = startScope ;
2013-03-05 15:28:40 +01:00
// absolute path - directly start in global scope
if ( startTok - > str ( ) = = " :: " ) {
startTok = startTok - > next ( ) ;
2017-07-16 01:14:15 +02:00
start_scope = & scopeList . front ( ) ;
2013-03-05 13:33:38 +01:00
}
2012-11-30 06:03:58 +01:00
2013-03-05 15:28:40 +01:00
const Token * tok = startTok ;
2017-07-16 01:14:15 +02:00
const Scope * scope = start_scope ;
2013-03-05 15:28:40 +01:00
2013-03-05 13:33:38 +01:00
while ( scope & & tok & & tok - > isName ( ) ) {
2018-05-06 08:23:07 +02:00
if ( tok - > strAt ( 1 ) = = " :: " | | ( tok - > strAt ( 1 ) = = " < " & & Token : : simpleMatch ( tok - > linkAt ( 1 ) , " > :: " ) ) ) {
2012-11-30 06:03:58 +01:00
scope = scope - > findRecordInNestedList ( tok - > str ( ) ) ;
2013-03-05 15:28:40 +01:00
if ( scope ) {
2018-05-01 07:32:19 +02:00
if ( tok - > strAt ( 1 ) = = " :: " )
tok = tok - > tokAt ( 2 ) ;
else
tok = tok - > linkAt ( 1 ) - > tokAt ( 2 ) ;
2013-03-05 15:28:40 +01:00
} else {
2017-07-16 01:14:15 +02:00
start_scope = start_scope - > nestedIn ;
if ( ! start_scope )
2013-03-05 15:28:40 +01:00
break ;
2017-07-16 01:14:15 +02:00
scope = start_scope ;
2013-03-05 15:28:40 +01:00
tok = startTok ;
}
2017-07-16 01:14:15 +02:00
} else {
const Type * type = scope - > findType ( tok - > str ( ) ) ;
if ( type )
return type ;
2022-07-28 22:53:59 +02:00
else if ( const Scope * scope1 = scope - > findRecordInBase ( tok - > str ( ) ) ) {
2021-01-18 19:01:04 +01:00
type = scope1 - > definedType ;
if ( type )
return type ;
2022-02-12 08:19:07 +01:00
} else if ( scope - > type = = Scope : : ScopeType : : eNamespace & & lookOutside ) {
scope = scope - > nestedIn ;
continue ;
2021-01-18 19:01:04 +01:00
} else
2017-07-16 01:14:15 +02:00
break ;
}
}
// check using namespaces
while ( startScope ) {
2022-06-08 16:58:57 +02:00
for ( std : : vector < Scope : : UsingInfo > : : const_iterator it = startScope - > usingList . begin ( ) ;
2017-07-16 01:14:15 +02:00
it ! = startScope - > usingList . end ( ) ; + + it ) {
tok = startTok ;
scope = it - > scope ;
start_scope = startScope ;
while ( scope & & tok & & tok - > isName ( ) ) {
2018-05-06 08:23:07 +02:00
if ( tok - > strAt ( 1 ) = = " :: " | | ( tok - > strAt ( 1 ) = = " < " & & Token : : simpleMatch ( tok - > linkAt ( 1 ) , " > :: " ) ) ) {
2017-07-16 01:14:15 +02:00
scope = scope - > findRecordInNestedList ( tok - > str ( ) ) ;
if ( scope ) {
2018-05-01 07:32:19 +02:00
if ( tok - > strAt ( 1 ) = = " :: " )
tok = tok - > tokAt ( 2 ) ;
else
tok = tok - > linkAt ( 1 ) - > tokAt ( 2 ) ;
2017-07-16 01:14:15 +02:00
} else {
start_scope = start_scope - > nestedIn ;
if ( ! start_scope )
break ;
scope = start_scope ;
tok = startTok ;
}
} else {
const Type * type = scope - > findType ( tok - > str ( ) ) ;
if ( type )
return type ;
2022-07-28 22:53:59 +02:00
else if ( const Scope * scope1 = scope - > findRecordInBase ( tok - > str ( ) ) ) {
2021-01-18 19:01:04 +01:00
type = scope1 - > definedType ;
if ( type )
return type ;
} else
2017-07-16 01:14:15 +02:00
break ;
}
}
}
startScope = startScope - > nestedIn ;
2012-11-30 06:03:58 +01:00
}
// not a valid path
2017-08-09 20:00:26 +02:00
return nullptr ;
2012-11-30 06:03:58 +01:00
}
2014-04-10 16:11:11 +02:00
2013-08-17 18:43:15 +02:00
//---------------------------------------------------------------------------
const Type * SymbolDatabase : : findTypeInNested ( const Token * startTok , const Scope * startScope ) const
{
// skip over struct or union
2016-04-22 06:02:54 +02:00
if ( Token : : Match ( startTok , " struct|union|enum " ) )
2013-08-17 18:43:15 +02:00
startTok = startTok - > next ( ) ;
// type same as scope
if ( startTok - > str ( ) = = startScope - > className & & startScope - > isClassOrStruct ( ) )
return startScope - > definedType ;
bool hasPath = false ;
// absolute path - directly start in global scope
if ( startTok - > str ( ) = = " :: " ) {
hasPath = true ;
startTok = startTok - > next ( ) ;
startScope = & scopeList . front ( ) ;
}
const Token * tok = startTok ;
const Scope * scope = startScope ;
while ( scope & & tok & & tok - > isName ( ) ) {
2018-05-06 08:23:07 +02:00
if ( tok - > strAt ( 1 ) = = " :: " | | ( tok - > strAt ( 1 ) = = " < " & & Token : : simpleMatch ( tok - > linkAt ( 1 ) , " > :: " ) ) ) {
2013-08-17 18:43:15 +02:00
hasPath = true ;
scope = scope - > findRecordInNestedList ( tok - > str ( ) ) ;
if ( scope ) {
2018-05-01 07:32:19 +02:00
if ( tok - > strAt ( 1 ) = = " :: " )
tok = tok - > tokAt ( 2 ) ;
else
tok = tok - > linkAt ( 1 ) - > tokAt ( 2 ) ;
2013-08-17 18:43:15 +02:00
} else {
startScope = startScope - > nestedIn ;
if ( ! startScope )
break ;
scope = startScope ;
tok = startTok ;
}
} else {
const Type * type = scope - > findType ( tok - > str ( ) ) ;
if ( hasPath | | type )
return type ;
else {
scope = scope - > nestedIn ;
if ( ! scope )
break ;
}
}
}
// not a valid path
2017-08-09 20:00:26 +02:00
return nullptr ;
2013-08-17 18:43:15 +02:00
}
2014-04-10 16:11:11 +02:00
//---------------------------------------------------------------------------
const Scope * SymbolDatabase : : findNamespace ( const Token * tok , const Scope * scope ) const
{
const Scope * s = findScope ( tok , scope ) ;
if ( s )
return s ;
else if ( scope - > nestedIn )
return findNamespace ( tok , scope - > nestedIn ) ;
2017-08-09 20:00:26 +02:00
return nullptr ;
2014-04-10 16:11:11 +02:00
}
//---------------------------------------------------------------------------
2019-07-22 11:25:51 +02:00
Function * SymbolDatabase : : findFunctionInScope ( const Token * func , const Scope * ns , const std : : string & path , nonneg int path_length )
2014-04-10 16:11:11 +02:00
{
2014-04-11 05:40:37 +02:00
const Function * function = nullptr ;
2015-01-12 06:11:22 +01:00
const bool destructor = func - > strAt ( - 1 ) = = " ~ " ;
2014-04-11 05:40:37 +02:00
2022-06-08 16:58:57 +02:00
auto range = ns - > functionMap . equal_range ( func - > str ( ) ) ;
for ( std : : multimap < std : : string , const Function * > : : const_iterator it = range . first ; it ! = range . second ; + + it ) {
2021-01-18 19:01:04 +01:00
if ( it - > second - > argsMatch ( ns , it - > second - > argDef , func - > next ( ) , path , path_length ) & &
2015-01-12 06:11:22 +01:00
it - > second - > isDestructor ( ) = = destructor ) {
2015-01-02 21:38:19 +01:00
function = it - > second ;
break ;
2014-04-11 05:40:37 +02:00
}
}
2014-04-10 16:11:11 +02:00
if ( ! function ) {
const Scope * scope = ns - > findRecordInNestedList ( func - > str ( ) ) ;
2018-05-01 07:32:19 +02:00
if ( scope & & Token : : Match ( func - > tokAt ( 1 ) , " ::|< " ) ) {
if ( func - > strAt ( 1 ) = = " :: " )
func = func - > tokAt ( 2 ) ;
2018-05-06 08:23:07 +02:00
else if ( func - > linkAt ( 1 ) )
2018-05-01 07:32:19 +02:00
func = func - > linkAt ( 1 ) - > tokAt ( 2 ) ;
2018-05-06 08:23:07 +02:00
else
return nullptr ;
2014-12-09 21:36:09 +01:00
if ( func - > str ( ) = = " ~ " )
func = func - > next ( ) ;
2018-05-01 07:32:19 +02:00
function = findFunctionInScope ( func , scope , path , path_length ) ;
2014-04-10 16:11:11 +02:00
}
}
return const_cast < Function * > ( function ) ;
}
2015-05-22 22:18:42 +02:00
//---------------------------------------------------------------------------
2015-06-18 19:07:51 +02:00
namespace {
2018-04-08 22:54:10 +02:00
2021-08-07 20:51:18 +02:00
# define C_KEYWORDS \
2020-11-29 15:01:29 +01:00
" _Alignas " , " _Alignof " , " _Atomic " , " _Bool " , " _Complex " , " _Generic " , " _Imaginary " , " _Noreturn " , \
" _Static_assert " , " _Thread_local " , " auto " , " break " , " case " , " char " , " const " , " continue " , " default " , \
" do " , " double " , " else " , " enum " , " extern " , " float " , " for " , " goto " , " if " , " inline " , " int " , " long " , \
" register " , " return " , " short " , " signed " , " sizeof " , " static " , " struct " , " switch " , " typedef " , \
" union " , " unsigned " , " void " , " volatile " , " while "
2018-04-08 22:54:10 +02:00
2021-01-16 13:52:09 +01:00
const std : : unordered_set < std : : string > c_keywords = { C_KEYWORDS , " restrict " } ;
const std : : unordered_set < std : : string > cpp_keywords = {
2018-04-08 22:54:10 +02:00
C_KEYWORDS ,
2020-11-29 15:01:29 +01:00
" alignas " , " alignof " , " and " , " and_eq " , " asm " , " bitand " , " bitor " , " bool " , " catch " , " char8_t " , " char16_t " ,
" char32_t " , " class " , " compl " , " concept " , " consteval " , " constexpr " , " constinit " , " const_cast " , " co_await " ,
" co_return " , " co_yield " , " decltype " ,
2018-06-17 17:05:36 +02:00
" delete " , " dynamic_cast " , " explicit " , " export " , " false " , " friend " ,
2018-04-08 22:54:10 +02:00
" mutable " , " namespace " , " new " , " noexcept " , " not " , " not_eq " , " nullptr " , " operator " ,
2018-06-17 17:05:36 +02:00
" or " , " or_eq " , " private " , " protected " , " public " , " reinterpret_cast " ,
" requires " , " static_assert " ,
" static_cast " , " template " , " this " , " thread_local " , " throw " ,
" true " , " try " , " typeid " , " typename " , " using " ,
" virtual " , " wchar_t " , " xor " , " xor_eq "
2018-04-08 22:54:10 +02:00
} ;
2015-06-18 19:07:51 +02:00
}
2015-11-29 13:23:13 +01:00
2015-06-18 19:07:51 +02:00
bool SymbolDatabase : : isReservedName ( const std : : string & iName ) const
{
2015-11-29 13:23:13 +01:00
if ( isCPP ( ) )
return cpp_keywords . find ( iName ) ! = cpp_keywords . cend ( ) ;
else
return c_keywords . find ( iName ) ! = c_keywords . cend ( ) ;
2015-05-22 22:18:42 +02:00
}
2015-10-04 19:42:58 +02:00
2019-07-22 11:25:51 +02:00
nonneg int SymbolDatabase : : sizeOfType ( const Token * type ) const
2016-07-08 20:53:08 +02:00
{
2019-07-22 11:25:51 +02:00
int size = mTokenizer - > sizeOfType ( type ) ;
2016-07-08 20:53:08 +02:00
2016-07-26 01:18:47 +02:00
if ( size = = 0 & & type - > type ( ) & & type - > type ( ) - > isEnumType ( ) & & type - > type ( ) - > classScope ) {
2018-06-16 16:10:28 +02:00
size = mSettings - > sizeof_int ;
2016-07-08 20:53:08 +02:00
const Token * enum_type = type - > type ( ) - > classScope - > enumType ;
if ( enum_type )
2018-06-16 16:10:28 +02:00
size = mTokenizer - > sizeOfType ( enum_type ) ;
2016-07-08 20:53:08 +02:00
}
return size ;
}
2022-06-15 21:25:55 +02:00
static const Token * parsedecl ( const Token * type ,
ValueType * const valuetype ,
ValueType : : Sign defaultSignedness ,
const Settings * settings ,
2022-08-21 17:11:22 +02:00
bool isCpp ,
2022-06-15 21:25:55 +02:00
SourceLocation loc = SourceLocation : : current ( ) ) ;
2015-10-11 10:48:08 +02:00
2022-06-15 21:25:55 +02:00
void SymbolDatabase : : setValueType ( Token * tok , const Variable & var , SourceLocation loc )
2015-10-11 10:48:08 +02:00
{
ValueType valuetype ;
2022-06-15 21:25:55 +02:00
if ( mSettings - > debugnormal | | mSettings - > debugwarnings )
valuetype . setDebugPath ( tok , loc ) ;
2018-05-02 20:55:11 +02:00
if ( var . nameToken ( ) )
valuetype . bits = var . nameToken ( ) - > bits ( ) ;
2015-10-11 10:48:08 +02:00
valuetype . pointer = var . dimensions ( ) . size ( ) ;
valuetype . typeScope = var . typeScope ( ) ;
2019-02-27 10:28:18 +01:00
if ( var . valueType ( ) ) {
valuetype . container = var . valueType ( ) - > container ;
2021-11-26 13:38:40 +01:00
valuetype . containerTypeToken = var . valueType ( ) - > containerTypeToken ;
2019-02-27 10:28:18 +01:00
}
2019-07-07 21:52:49 +02:00
valuetype . smartPointerType = var . smartPointerType ( ) ;
2022-08-21 17:11:22 +02:00
if ( parsedecl ( var . typeStartToken ( ) , & valuetype , mDefaultSignedness , mSettings , mIsCpp ) ) {
2019-02-24 19:11:18 +01:00
if ( tok - > str ( ) = = " . " & & tok - > astOperand1 ( ) ) {
const ValueType * const vt = tok - > astOperand1 ( ) - > valueType ( ) ;
if ( vt & & ( vt - > constness & 1 ) ! = 0 )
valuetype . constness | = 1 ;
}
2017-03-22 02:55:22 +01:00
setValueType ( tok , valuetype ) ;
2019-02-24 19:11:18 +01:00
}
2016-04-22 06:02:54 +02:00
}
2022-06-15 21:25:55 +02:00
void SymbolDatabase : : setValueType ( Token * tok , const Enumerator & enumerator , SourceLocation loc )
2016-04-22 06:02:54 +02:00
{
ValueType valuetype ;
2022-06-15 21:25:55 +02:00
if ( mSettings - > debugnormal | | mSettings - > debugwarnings )
valuetype . setDebugPath ( tok , loc ) ;
2016-04-22 06:02:54 +02:00
valuetype . typeScope = enumerator . scope ;
const Token * type = enumerator . scope - > enumType ;
if ( type ) {
2017-03-04 11:13:28 +01:00
valuetype . type = ValueType : : typeFromString ( type - > str ( ) , type - > isLong ( ) ) ;
if ( valuetype . type = = ValueType : : Type : : UNKNOWN_TYPE & & type - > isStandardType ( ) )
2018-06-16 16:10:28 +02:00
valuetype . fromLibraryType ( type - > str ( ) , mSettings ) ;
2017-03-04 11:13:28 +01:00
if ( valuetype . isIntegral ( ) ) {
if ( type - > isSigned ( ) )
valuetype . sign = ValueType : : Sign : : SIGNED ;
else if ( type - > isUnsigned ( ) )
valuetype . sign = ValueType : : Sign : : UNSIGNED ;
else if ( valuetype . type = = ValueType : : Type : : CHAR )
2018-06-16 23:25:35 +02:00
valuetype . sign = mDefaultSignedness ;
2017-03-04 11:13:28 +01:00
else
valuetype . sign = ValueType : : Sign : : SIGNED ;
2016-05-04 15:39:56 +02:00
}
2016-04-22 06:02:54 +02:00
2017-03-22 02:55:22 +01:00
setValueType ( tok , valuetype ) ;
2016-04-22 06:02:54 +02:00
} else {
valuetype . sign = ValueType : : SIGNED ;
valuetype . type = ValueType : : INT ;
2017-03-22 02:55:22 +01:00
setValueType ( tok , valuetype ) ;
2016-04-22 06:02:54 +02:00
}
2015-10-11 10:48:08 +02:00
}
2017-02-27 23:04:25 +01:00
static void setAutoTokenProperties ( Token * const autoTok )
{
const ValueType * valuetype = autoTok - > valueType ( ) ;
if ( valuetype - > isIntegral ( ) | | valuetype - > isFloat ( ) )
autoTok - > isStandardType ( true ) ;
}
2021-08-14 19:00:58 +02:00
static bool isContainerYieldElement ( Library : : Container : : Yield yield )
{
return yield = = Library : : Container : : Yield : : ITEM | | yield = = Library : : Container : : Yield : : AT_INDEX | |
yield = = Library : : Container : : Yield : : BUFFER | | yield = = Library : : Container : : Yield : : BUFFER_NT ;
}
static bool isContainerYieldPointer ( Library : : Container : : Yield yield )
{
return yield = = Library : : Container : : Yield : : BUFFER | | yield = = Library : : Container : : Yield : : BUFFER_NT ;
}
2022-06-15 21:25:55 +02:00
void SymbolDatabase : : setValueType ( Token * tok , const ValueType & valuetype , SourceLocation loc )
2015-10-04 19:42:58 +02:00
{
2022-06-15 21:25:55 +02:00
ValueType * valuetypePtr = new ValueType ( valuetype ) ;
if ( mSettings - > debugnormal | | mSettings - > debugwarnings )
valuetypePtr - > setDebugPath ( tok , loc ) ;
tok - > setValueType ( valuetypePtr ) ;
2019-06-16 10:09:38 +02:00
Token * parent = tok - > astParent ( ) ;
2015-10-04 19:42:58 +02:00
if ( ! parent | | parent - > valueType ( ) )
return ;
2016-02-04 20:49:13 +01:00
if ( ! parent - > astOperand1 ( ) )
2015-10-04 19:42:58 +02:00
return ;
2016-02-04 20:49:13 +01:00
const ValueType * vt1 = parent - > astOperand1 ( ) ? parent - > astOperand1 ( ) - > valueType ( ) : nullptr ;
const ValueType * vt2 = parent - > astOperand2 ( ) ? parent - > astOperand2 ( ) - > valueType ( ) : nullptr ;
if ( vt1 & & Token : : Match ( parent , " <<|>> " ) ) {
2020-01-27 11:46:59 +01:00
if ( ! mIsCpp | | ( vt2 & & vt2 - > isIntegral ( ) ) ) {
2020-09-05 12:07:06 +02:00
if ( vt1 - > type < ValueType : : Type : : BOOL | | vt1 - > type > = ValueType : : Type : : INT ) {
ValueType vt ( * vt1 ) ;
vt . reference = Reference : : None ;
setValueType ( parent , vt ) ;
} else {
2020-01-27 11:46:59 +01:00
ValueType vt ( * vt1 ) ;
vt . type = ValueType : : Type : : INT ; // Integer promotion
vt . sign = ValueType : : Sign : : SIGNED ;
2020-09-05 12:07:06 +02:00
vt . reference = Reference : : None ;
2020-01-27 11:46:59 +01:00
setValueType ( parent , vt ) ;
}
}
2015-12-31 20:18:35 +01:00
return ;
}
2021-08-14 19:00:58 +02:00
if ( vt1 & & vt1 - > container & & vt1 - > containerTypeToken & & Token : : Match ( parent , " . %name% ( " ) & &
isContainerYieldElement ( vt1 - > container - > getYield ( parent - > next ( ) - > str ( ) ) ) ) {
2020-06-26 22:47:28 +02:00
ValueType item ;
2022-08-21 17:11:22 +02:00
if ( parsedecl ( vt1 - > containerTypeToken , & item , mDefaultSignedness , mSettings , mIsCpp ) ) {
2021-08-14 19:00:58 +02:00
if ( item . constness = = 0 )
item . constness = vt1 - > constness ;
if ( isContainerYieldPointer ( vt1 - > container - > getYield ( parent - > next ( ) - > str ( ) ) ) )
item . pointer + = 1 ;
else
item . reference = Reference : : LValue ;
2020-06-26 22:47:28 +02:00
setValueType ( parent - > tokAt ( 2 ) , item ) ;
2021-08-14 19:00:58 +02:00
}
2020-06-26 22:47:28 +02:00
}
2019-07-09 17:32:19 +02:00
if ( vt1 & & vt1 - > smartPointerType & & Token : : Match ( parent , " . %name% ( " ) & & parent - > originalName ( ) = = " -> " & & ! parent - > next ( ) - > function ( ) ) {
2019-07-13 20:29:15 +02:00
const Scope * scope = vt1 - > smartPointerType - > classScope ;
2019-07-09 17:32:19 +02:00
const Function * f = scope ? scope - > findFunction ( parent - > next ( ) , false ) : nullptr ;
if ( f )
parent - > next ( ) - > function ( f ) ;
}
2016-03-21 19:51:09 +01:00
if ( parent - > isAssignmentOp ( ) ) {
2020-09-03 18:44:44 +02:00
if ( vt1 ) {
auto vt = * vt1 ;
vt . reference = Reference : : None ;
setValueType ( parent , vt ) ;
} else if ( mIsCpp & & ( ( Token : : Match ( parent - > tokAt ( - 3 ) , " %var% ; % var % = " ) && parent->strAt(-3) == parent->strAt(-1)) ||
2020-09-03 18:55:40 +02:00
Token : : Match ( parent - > tokAt ( - 1 ) , " %var% = " ) ) ) {
2017-04-20 21:22:57 +02:00
Token * var1Tok = parent - > strAt ( - 2 ) = = " ; " ? parent - > tokAt ( - 3 ) : parent - > tokAt ( - 1 ) ;
2017-02-26 22:43:10 +01:00
Token * autoTok = nullptr ;
2021-11-24 16:51:40 +01:00
if ( Token : : Match ( var1Tok - > tokAt ( - 2 ) , " ;|{|}|(|const|constexpr auto " ) )
2017-02-26 22:43:10 +01:00
autoTok = var1Tok - > previous ( ) ;
2022-01-21 09:56:55 +01:00
else if ( Token : : Match ( var1Tok - > tokAt ( - 3 ) , " ; | { | } | ( | const | constexpr auto * | & | & & " ))
2017-02-26 22:43:10 +01:00
autoTok = var1Tok - > tokAt ( - 2 ) ;
if ( autoTok ) {
2017-03-23 03:09:40 +01:00
ValueType vt ( * vt2 ) ;
2019-02-24 19:11:18 +01:00
if ( vt . constness & ( 1 < < vt . pointer ) )
vt . constness & = ~ ( 1 < < vt . pointer ) ;
2017-03-23 03:09:40 +01:00
if ( autoTok - > strAt ( 1 ) = = " * " & & vt . pointer )
vt . pointer - - ;
2021-11-24 16:51:40 +01:00
if ( Token : : Match ( autoTok - > tokAt ( - 1 ) , " const|constexpr " ) )
2017-03-23 03:09:40 +01:00
vt . constness | = 1 ;
setValueType ( autoTok , vt ) ;
2017-02-27 23:04:25 +01:00
setAutoTokenProperties ( autoTok ) ;
2019-02-24 19:11:18 +01:00
if ( vt2 - > pointer > vt . pointer )
vt . pointer + + ;
2019-02-23 18:15:05 +01:00
setValueType ( var1Tok , vt ) ;
if ( var1Tok ! = parent - > previous ( ) )
2019-02-24 19:11:18 +01:00
setValueType ( parent - > previous ( ) , vt ) ;
2017-04-21 21:25:02 +02:00
Variable * var = const_cast < Variable * > ( parent - > previous ( ) - > variable ( ) ) ;
2017-03-23 03:09:40 +01:00
if ( var ) {
2019-02-24 08:16:08 +01:00
ValueType vt2_ ( * vt2 ) ;
if ( vt2_ . pointer = = 0 & & autoTok - > strAt ( 1 ) = = " * " )
vt2_ . pointer = 1 ;
if ( ( vt . constness & ( 1 < < vt2 - > pointer ) ) ! = 0 )
vt2_ . constness | = ( 1 < < vt2 - > pointer ) ;
2019-05-14 08:57:36 +02:00
if ( ! Token : : Match ( autoTok - > tokAt ( 1 ) , " *|& " ) )
vt2_ . constness = vt . constness ;
2019-02-24 08:16:08 +01:00
var - > setValueType ( vt2_ ) ;
2017-03-23 03:09:40 +01:00
if ( vt2 - > typeScope & & vt2 - > typeScope - > definedType ) {
2017-04-21 21:25:02 +02:00
var - > type ( vt2 - > typeScope - > definedType ) ;
2017-03-23 03:09:40 +01:00
if ( autoTok - > valueType ( ) - > pointer = = 0 )
autoTok - > type ( vt2 - > typeScope - > definedType ) ;
}
}
2017-02-26 20:02:57 +01:00
}
}
2016-03-21 19:51:09 +01:00
return ;
}
2018-06-16 23:30:00 +02:00
if ( parent - > str ( ) = = " [ " & & ( ! mIsCpp | | parent - > astOperand1 ( ) = = tok ) & & valuetype . pointer > 0U & & ! Token : : Match ( parent - > previous ( ) , " [{,] " ) ) {
2017-03-30 11:01:29 +02:00
const Token * op1 = parent - > astOperand1 ( ) ;
while ( op1 & & op1 - > str ( ) = = " [ " )
op1 = op1 - > astOperand1 ( ) ;
2015-12-30 11:36:46 +01:00
ValueType vt ( valuetype ) ;
2017-03-30 11:01:29 +02:00
// the "[" is a dereference unless this is a variable declaration
if ( ! ( op1 & & op1 - > variable ( ) & & op1 - > variable ( ) - > nameToken ( ) = = op1 ) )
vt . pointer - = 1U ;
2017-03-22 02:55:22 +01:00
setValueType ( parent , vt ) ;
2015-10-04 19:42:58 +02:00
return ;
}
2016-12-04 16:02:50 +01:00
if ( Token : : Match ( parent - > previous ( ) , " %name% ( " ) & & parent - > astOperand1 ( ) = = tok & & valuetype . pointer > 0U ) {
ValueType vt ( valuetype ) ;
vt . pointer - = 1U ;
2017-03-22 02:55:22 +01:00
setValueType ( parent , vt ) ;
2016-12-04 16:02:50 +01:00
return ;
}
2019-10-05 19:57:52 +02:00
// std::move
if ( vt2 & & parent - > str ( ) = = " ( " & & Token : : simpleMatch ( parent - > tokAt ( - 3 ) , " std :: move ( " ) ) {
2020-09-11 05:38:31 +02:00
ValueType vt = valuetype ;
vt . reference = Reference : : RValue ;
setValueType ( parent , vt ) ;
2019-10-05 19:57:52 +02:00
return ;
}
2015-10-07 20:24:17 +02:00
if ( parent - > str ( ) = = " * " & & ! parent - > astOperand2 ( ) & & valuetype . pointer > 0U ) {
2015-12-30 11:36:46 +01:00
ValueType vt ( valuetype ) ;
vt . pointer - = 1U ;
2017-03-22 02:55:22 +01:00
setValueType ( parent , vt ) ;
2015-10-04 19:42:58 +02:00
return ;
}
2021-08-14 19:00:58 +02:00
// Dereference iterator
if ( parent - > str ( ) = = " * " & & ! parent - > astOperand2 ( ) & & valuetype . type = = ValueType : : Type : : ITERATOR & &
valuetype . containerTypeToken ) {
ValueType vt ;
2022-08-21 17:11:22 +02:00
if ( parsedecl ( valuetype . containerTypeToken , & vt , mDefaultSignedness , mSettings , mIsCpp ) ) {
2021-08-14 19:00:58 +02:00
if ( vt . constness = = 0 )
vt . constness = valuetype . constness ;
vt . reference = Reference : : LValue ;
setValueType ( parent , vt ) ;
return ;
}
}
// Dereference smart pointer
if ( parent - > str ( ) = = " * " & & ! parent - > astOperand2 ( ) & & valuetype . type = = ValueType : : Type : : SMART_POINTER & &
valuetype . smartPointerTypeToken ) {
ValueType vt ;
2022-08-21 17:11:22 +02:00
if ( parsedecl ( valuetype . smartPointerTypeToken , & vt , mDefaultSignedness , mSettings , mIsCpp ) ) {
2021-08-14 19:00:58 +02:00
if ( vt . constness = = 0 )
vt . constness = valuetype . constness ;
setValueType ( parent , vt ) ;
return ;
}
}
2019-03-19 06:25:10 +01:00
if ( parent - > str ( ) = = " * " & & Token : : simpleMatch ( parent - > astOperand2 ( ) , " [ " ) & & valuetype . pointer > 0U ) {
const Token * op1 = parent - > astOperand2 ( ) - > astOperand1 ( ) ;
while ( op1 & & op1 - > str ( ) = = " [ " )
op1 = op1 - > astOperand1 ( ) ;
2021-01-02 19:10:25 +01:00
const ValueType & vt ( valuetype ) ;
2019-03-19 06:25:10 +01:00
if ( op1 & & op1 - > variable ( ) & & op1 - > variable ( ) - > nameToken ( ) = = op1 ) {
setValueType ( parent , vt ) ;
return ;
}
}
2015-10-08 19:50:10 +02:00
if ( parent - > str ( ) = = " & " & & ! parent - > astOperand2 ( ) ) {
2015-12-30 11:36:46 +01:00
ValueType vt ( valuetype ) ;
2020-09-03 18:44:44 +02:00
vt . reference = Reference : : None ; //Given int& x; the type of &x is int* not int&*
2015-12-30 11:36:46 +01:00
vt . pointer + = 1U ;
2017-03-22 02:55:22 +01:00
setValueType ( parent , vt ) ;
2015-10-08 19:50:10 +02:00
return ;
}
2015-10-04 19:42:58 +02:00
2016-02-04 20:49:13 +01:00
if ( ( parent - > str ( ) = = " . " | | parent - > str ( ) = = " :: " ) & &
parent - > astOperand2 ( ) & & parent - > astOperand2 ( ) - > isName ( ) ) {
const Variable * var = parent - > astOperand2 ( ) - > variable ( ) ;
if ( ! var & & valuetype . typeScope & & vt1 ) {
const std : : string & name = parent - > astOperand2 ( ) - > str ( ) ;
const Scope * typeScope = vt1 - > typeScope ;
if ( ! typeScope )
2015-10-11 10:48:08 +02:00
return ;
2016-02-04 20:49:13 +01:00
for ( std : : list < Variable > : : const_iterator it = typeScope - > varlist . begin ( ) ; it ! = typeScope - > varlist . end ( ) ; + + it ) {
if ( it - > nameToken ( ) - > str ( ) = = name ) {
var = & * it ;
break ;
}
2015-10-11 10:48:08 +02:00
}
}
2016-02-04 20:49:13 +01:00
if ( var )
2017-03-22 02:55:22 +01:00
setValueType ( parent , * var ) ;
2016-02-04 20:49:13 +01:00
return ;
2015-10-11 10:48:08 +02:00
}
2017-02-27 02:09:33 +01:00
// range for loop, auto
if ( vt2 & &
parent - > str ( ) = = " : " & &
2022-05-20 08:48:01 +02:00
Token : : Match ( parent - > astParent ( ) , " ( const| auto *|&| %var% : " ) & & // TODO: east-const, multiple const, ref to ptr, rvalue ref
2017-02-27 02:09:33 +01:00
! parent - > previous ( ) - > valueType ( ) & &
Token : : simpleMatch ( parent - > astParent ( ) - > astOperand1 ( ) , " for " ) ) {
2017-03-24 00:48:20 +01:00
const bool isconst = Token : : simpleMatch ( parent - > astParent ( ) - > next ( ) , " const " ) ;
2019-06-16 10:09:38 +02:00
Token * const autoToken = parent - > astParent ( ) - > tokAt ( isconst ? 2 : 1 ) ;
2017-02-27 02:09:33 +01:00
if ( vt2 - > pointer ) {
2017-03-24 00:48:20 +01:00
ValueType autovt ( * vt2 ) ;
autovt . pointer - - ;
autovt . constness = 0 ;
setValueType ( autoToken , autovt ) ;
2017-02-27 23:04:25 +01:00
setAutoTokenProperties ( autoToken ) ;
2017-03-24 00:48:20 +01:00
ValueType varvt ( * vt2 ) ;
varvt . pointer - - ;
2022-05-20 08:48:01 +02:00
if ( Token : : simpleMatch ( autoToken - > next ( ) , " & " ) )
varvt . reference = Reference : : LValue ;
if ( isconst ) {
if ( varvt . pointer & & varvt . reference ! = Reference : : None )
varvt . constness | = 2 ;
else
varvt . constness | = 1 ;
}
2017-03-24 00:48:20 +01:00
setValueType ( parent - > previous ( ) , varvt ) ;
2017-05-01 20:12:50 +02:00
Variable * var = const_cast < Variable * > ( parent - > previous ( ) - > variable ( ) ) ;
if ( var ) {
2018-06-20 10:00:15 +02:00
var - > setValueType ( varvt ) ;
2017-05-01 20:12:50 +02:00
if ( vt2 - > typeScope & & vt2 - > typeScope - > definedType ) {
var - > type ( vt2 - > typeScope - > definedType ) ;
autoToken - > type ( vt2 - > typeScope - > definedType ) ;
}
2017-03-24 00:48:20 +01:00
}
2017-03-05 15:40:29 +01:00
} else if ( vt2 - > container ) {
// TODO: Determine exact type of RHS
const Token * typeStart = parent - > astOperand2 ( ) ;
while ( typeStart ) {
if ( typeStart - > variable ( ) )
typeStart = typeStart - > variable ( ) - > typeStartToken ( ) ;
else if ( typeStart - > str ( ) = = " ( " & & typeStart - > previous ( ) & & typeStart - > previous ( ) - > function ( ) )
typeStart = typeStart - > previous ( ) - > function ( ) - > retDef ;
else
break ;
}
2019-07-09 17:32:19 +02:00
// Try to determine type of "auto" token.
2017-03-05 15:40:29 +01:00
// TODO: Get type better
2019-07-09 17:32:19 +02:00
bool setType = false ;
ValueType autovt ;
const Type * templateArgType = nullptr ; // container element type / smart pointer type
2021-12-11 15:16:54 +01:00
if ( ! vt2 - > container - > rangeItemRecordType . empty ( ) ) {
setType = true ;
autovt . type = ValueType : : Type : : RECORD ;
} else if ( vt2 - > containerTypeToken ) {
2019-10-23 11:52:00 +02:00
if ( mSettings - > library . isSmartPointer ( vt2 - > containerTypeToken ) ) {
const Token * smartPointerTypeTok = vt2 - > containerTypeToken ;
while ( Token : : Match ( smartPointerTypeTok , " %name%|:: " ) )
smartPointerTypeTok = smartPointerTypeTok - > next ( ) ;
if ( Token : : Match ( smartPointerTypeTok , " < %name% > > " ) & & smartPointerTypeTok - > next ( ) - > type ( ) ) {
setType = true ;
templateArgType = smartPointerTypeTok - > next ( ) - > type ( ) ;
autovt . smartPointerType = templateArgType ;
autovt . type = ValueType : : Type : : NONSTD ;
}
2022-08-21 17:11:22 +02:00
} else if ( parsedecl ( vt2 - > containerTypeToken , & autovt , mDefaultSignedness , mSettings , mIsCpp ) ) {
2019-07-09 17:32:19 +02:00
setType = true ;
2019-10-23 11:52:00 +02:00
templateArgType = vt2 - > containerTypeToken - > type ( ) ;
2019-07-09 17:32:19 +02:00
}
}
if ( setType ) {
// Type of "auto" has been determined.. set type information for "auto" and variable tokens
setValueType ( autoToken , autovt ) ;
setAutoTokenProperties ( autoToken ) ;
ValueType varvt ( autovt ) ;
if ( isconst )
2022-06-03 19:24:59 +02:00
varvt . constness | = 1 ;
2019-07-09 17:32:19 +02:00
setValueType ( parent - > previous ( ) , varvt ) ;
Variable * var = const_cast < Variable * > ( parent - > previous ( ) - > variable ( ) ) ;
if ( var ) {
var - > setValueType ( varvt ) ;
if ( templateArgType & & templateArgType - > classScope & & templateArgType - > classScope - > definedType ) {
autoToken - > type ( templateArgType - > classScope - > definedType ) ;
var - > type ( templateArgType - > classScope - > definedType ) ;
2017-03-24 01:14:49 +01:00
}
2017-03-05 15:40:29 +01:00
}
}
2017-02-27 02:09:33 +01:00
}
}
2018-04-06 22:26:35 +02:00
if ( vt1 & & vt1 - > containerTypeToken & & parent - > str ( ) = = " [ " ) {
ValueType vtParent ;
2022-08-21 17:11:22 +02:00
if ( parsedecl ( vt1 - > containerTypeToken , & vtParent , mDefaultSignedness , mSettings , mIsCpp ) ) {
2018-04-06 22:26:35 +02:00
setValueType ( parent , vtParent ) ;
return ;
}
}
2020-11-16 20:11:26 +01:00
if ( mIsCpp & & vt2 & & Token : : simpleMatch ( parent - > previous ( ) , " decltype ( " ) ) {
setValueType ( parent , * vt2 ) ;
return ;
}
2021-04-25 10:38:33 +02:00
// c++17 auto type deduction of braced init list
if ( mIsCpp & & mSettings - > standards . cpp > = Standards : : CPP17 & & vt2 & & Token : : Match ( parent - > tokAt ( - 2 ) , " auto %var% { " ) ) {
Token * autoTok = parent - > tokAt ( - 2 ) ;
setValueType ( autoTok , * vt2 ) ;
setAutoTokenProperties ( autoTok ) ;
2022-01-15 07:56:56 +01:00
if ( parent - > previous ( ) - > variable ( ) )
const_cast < Variable * > ( parent - > previous ( ) - > variable ( ) ) - > setValueType ( * vt2 ) ;
else
debugMessage ( parent - > previous ( ) , " debug " , " Missing variable class for variable with varid " ) ;
2021-04-25 10:38:33 +02:00
return ;
}
2016-02-04 20:49:13 +01:00
if ( ! vt1 )
2015-10-04 19:42:58 +02:00
return ;
2016-02-04 20:49:13 +01:00
if ( parent - > astOperand2 ( ) & & ! vt2 )
return ;
2018-04-04 21:51:31 +02:00
const bool ternary = parent - > str ( ) = = " : " & & parent - > astParent ( ) & & parent - > astParent ( ) - > str ( ) = = " ? " ;
2017-07-01 22:45:51 +02:00
if ( ternary ) {
2017-08-02 07:48:11 +02:00
if ( vt2 & & vt1 - > pointer = = vt2 - > pointer & & vt1 - > type = = vt2 - > type & & vt1 - > sign = = vt2 - > sign )
2017-07-01 22:45:51 +02:00
setValueType ( parent , * vt2 ) ;
2019-06-16 10:09:38 +02:00
parent = parent - > astParent ( ) ;
2017-07-01 22:45:51 +02:00
}
2016-02-04 21:20:05 +01:00
2016-02-05 12:06:44 +01:00
if ( ternary | | parent - > isArithmeticalOp ( ) | | parent - > tokType ( ) = = Token : : eIncDecOp ) {
2020-12-05 13:24:21 +01:00
// CONTAINER + x => CONTAINER
if ( parent - > str ( ) = = " + " & & vt1 - > type = = ValueType : : Type : : CONTAINER & & vt2 & & vt2 - > isIntegral ( ) ) {
2020-12-01 20:16:39 +01:00
setValueType ( parent , * vt1 ) ;
return ;
}
2020-12-05 13:24:21 +01:00
// x + CONTAINER => CONTAINER
if ( parent - > str ( ) = = " + " & & vt1 - > isIntegral ( ) & & vt2 & & vt2 - > type = = ValueType : : Type : : CONTAINER ) {
2020-12-01 20:16:39 +01:00
setValueType ( parent , * vt2 ) ;
return ;
}
2016-02-04 21:03:54 +01:00
if ( vt1 - > pointer ! = 0U & & vt2 & & vt2 - > pointer = = 0U ) {
2017-03-22 02:55:22 +01:00
setValueType ( parent , * vt1 ) ;
2015-10-04 19:42:58 +02:00
return ;
}
2016-02-04 21:03:54 +01:00
if ( vt1 - > pointer = = 0U & & vt2 & & vt2 - > pointer ! = 0U ) {
2017-03-22 02:55:22 +01:00
setValueType ( parent , * vt2 ) ;
2015-10-04 19:42:58 +02:00
return ;
}
2016-02-05 09:59:27 +01:00
if ( vt1 - > pointer ! = 0U ) {
2016-02-05 12:06:44 +01:00
if ( ternary | | parent - > tokType ( ) = = Token : : eIncDecOp ) // result is pointer
2017-03-22 02:55:22 +01:00
setValueType ( parent , * vt1 ) ;
2016-02-05 09:59:27 +01:00
else // result is pointer diff
2017-03-22 02:55:22 +01:00
setValueType ( parent , ValueType ( ValueType : : Sign : : SIGNED , ValueType : : Type : : INT , 0U , 0U , " ptrdiff_t " ) ) ;
2015-10-04 19:42:58 +02:00
return ;
}
2016-02-04 21:03:54 +01:00
if ( vt1 - > type = = ValueType : : Type : : LONGDOUBLE | | ( vt2 & & vt2 - > type = = ValueType : : Type : : LONGDOUBLE ) ) {
2017-03-22 02:55:22 +01:00
setValueType ( parent , ValueType ( ValueType : : Sign : : UNKNOWN_SIGN , ValueType : : Type : : LONGDOUBLE , 0U ) ) ;
2015-10-08 19:50:10 +02:00
return ;
}
2016-02-04 21:03:54 +01:00
if ( vt1 - > type = = ValueType : : Type : : DOUBLE | | ( vt2 & & vt2 - > type = = ValueType : : Type : : DOUBLE ) ) {
2017-03-22 02:55:22 +01:00
setValueType ( parent , ValueType ( ValueType : : Sign : : UNKNOWN_SIGN , ValueType : : Type : : DOUBLE , 0U ) ) ;
2015-10-04 19:42:58 +02:00
return ;
}
2016-02-04 21:03:54 +01:00
if ( vt1 - > type = = ValueType : : Type : : FLOAT | | ( vt2 & & vt2 - > type = = ValueType : : Type : : FLOAT ) ) {
2017-03-22 02:55:22 +01:00
setValueType ( parent , ValueType ( ValueType : : Sign : : UNKNOWN_SIGN , ValueType : : Type : : FLOAT , 0U ) ) ;
2015-10-04 19:42:58 +02:00
return ;
}
2017-07-16 17:27:32 +02:00
// iterator +/- integral = iterator
if ( vt1 - > type = = ValueType : : Type : : ITERATOR & & vt2 & & vt2 - > isIntegral ( ) & &
( parent - > str ( ) = = " + " | | parent - > str ( ) = = " - " ) ) {
setValueType ( parent , * vt1 ) ;
return ;
}
2019-10-23 12:42:46 +02:00
if ( parent - > str ( ) = = " + " & & vt1 - > type = = ValueType : : Type : : CONTAINER & & vt2 & & vt2 - > type = = ValueType : : Type : : CONTAINER & & vt1 - > container = = vt2 - > container ) {
setValueType ( parent , * vt1 ) ;
return ;
}
2015-10-11 12:20:40 +02:00
}
2015-10-07 18:10:48 +02:00
2016-02-04 21:03:54 +01:00
if ( vt1 - > isIntegral ( ) & & vt1 - > pointer = = 0U & &
( ! vt2 | | ( vt2 - > isIntegral ( ) & & vt2 - > pointer = = 0U ) ) & &
2016-02-05 12:06:44 +01:00
( ternary | | parent - > isArithmeticalOp ( ) | | parent - > tokType ( ) = = Token : : eBitOp | | parent - > tokType ( ) = = Token : : eIncDecOp | | parent - > isAssignmentOp ( ) ) ) {
2015-10-11 12:20:40 +02:00
ValueType vt ;
2016-02-04 21:03:54 +01:00
if ( ! vt2 | | vt1 - > type > vt2 - > type ) {
vt . type = vt1 - > type ;
vt . sign = vt1 - > sign ;
vt . originalTypeName = vt1 - > originalTypeName ;
} else if ( vt1 - > type = = vt2 - > type ) {
2015-10-11 12:20:40 +02:00
vt . type = vt1 - > type ;
if ( vt1 - > sign = = ValueType : : Sign : : UNSIGNED | | vt2 - > sign = = ValueType : : Sign : : UNSIGNED )
vt . sign = ValueType : : Sign : : UNSIGNED ;
else if ( vt1 - > sign = = ValueType : : Sign : : UNKNOWN_SIGN | | vt2 - > sign = = ValueType : : Sign : : UNKNOWN_SIGN )
vt . sign = ValueType : : Sign : : UNKNOWN_SIGN ;
else
vt . sign = ValueType : : Sign : : SIGNED ;
vt . originalTypeName = ( vt1 - > originalTypeName . empty ( ) ? vt2 : vt1 ) - > originalTypeName ;
} else {
vt . type = vt2 - > type ;
vt . sign = vt2 - > sign ;
vt . originalTypeName = vt2 - > originalTypeName ;
}
2019-09-01 09:51:53 +02:00
if ( vt . type < ValueType : : Type : : INT & & ! ( ternary & & vt . type = = ValueType : : Type : : BOOL ) ) {
2015-10-11 12:20:40 +02:00
vt . type = ValueType : : Type : : INT ;
vt . sign = ValueType : : Sign : : SIGNED ;
vt . originalTypeName . clear ( ) ;
2015-10-04 19:42:58 +02:00
}
2015-10-11 12:20:40 +02:00
2017-03-22 02:55:22 +01:00
setValueType ( parent , vt ) ;
2015-10-11 12:20:40 +02:00
return ;
2015-10-04 19:42:58 +02:00
}
}
2022-06-15 21:25:55 +02:00
static const Token * parsedecl ( const Token * type ,
ValueType * const valuetype ,
ValueType : : Sign defaultSignedness ,
const Settings * settings ,
2022-08-21 17:11:22 +02:00
bool isCpp ,
2022-06-15 21:25:55 +02:00
SourceLocation loc )
2015-10-04 20:32:16 +02:00
{
2022-06-15 21:25:55 +02:00
if ( settings - > debugnormal | | settings - > debugwarnings )
valuetype - > setDebugPath ( type , loc ) ;
2019-09-01 11:36:02 +02:00
const Token * const previousType = type ;
2015-10-10 08:32:45 +02:00
const unsigned int pointer0 = valuetype - > pointer ;
2020-02-14 09:40:27 +01:00
while ( Token : : Match ( type - > previous ( ) , " %name% " ) & & ! endsWith ( type - > previous ( ) - > str ( ) , ' : ' ) )
2015-10-10 08:32:45 +02:00
type = type - > previous ( ) ;
2016-01-01 20:03:31 +01:00
valuetype - > sign = ValueType : : Sign : : UNKNOWN_SIGN ;
2019-07-07 21:52:49 +02:00
if ( ! valuetype - > typeScope & & ! valuetype - > smartPointerType )
2016-05-09 11:11:13 +02:00
valuetype - > type = ValueType : : Type : : UNKNOWN_TYPE ;
2019-07-07 21:52:49 +02:00
else if ( valuetype - > smartPointerType )
2021-08-14 19:00:58 +02:00
valuetype - > type = ValueType : : Type : : SMART_POINTER ;
2016-08-26 19:47:36 +02:00
else if ( valuetype - > typeScope - > type = = Scope : : eEnum ) {
const Token * enum_type = valuetype - > typeScope - > enumType ;
if ( enum_type ) {
if ( enum_type - > isSigned ( ) )
valuetype - > sign = ValueType : : Sign : : SIGNED ;
else if ( enum_type - > isUnsigned ( ) )
valuetype - > sign = ValueType : : Sign : : UNSIGNED ;
else
valuetype - > sign = defaultSignedness ;
2018-04-04 21:51:31 +02:00
const ValueType : : Type t = ValueType : : typeFromString ( enum_type - > str ( ) , enum_type - > isLong ( ) ) ;
2017-03-04 11:13:28 +01:00
if ( t ! = ValueType : : Type : : UNKNOWN_TYPE )
2017-03-01 18:09:50 +01:00
valuetype - > type = t ;
else if ( enum_type - > isStandardType ( ) )
2016-08-26 19:47:36 +02:00
valuetype - > fromLibraryType ( enum_type - > str ( ) , settings ) ;
} else
valuetype - > type = ValueType : : Type : : INT ;
} else
2017-03-05 14:53:32 +01:00
valuetype - > type = ValueType : : Type : : RECORD ;
2020-04-10 11:53:32 +02:00
bool par = false ;
2020-09-03 18:44:44 +02:00
while ( Token : : Match ( type , " %name%|*|&|&&|::|( " ) & & ! Token : : Match ( type , " typename|template " ) & & type - > varId ( ) = = 0 & &
2019-06-28 22:07:21 +02:00
! type - > variable ( ) & & ! type - > function ( ) ) {
2022-04-07 06:47:15 +02:00
bool isIterator = false ;
2020-04-10 11:53:32 +02:00
if ( type - > str ( ) = = " ( " ) {
2020-06-10 21:13:53 +02:00
if ( Token : : Match ( type - > link ( ) , " ) const| { " ) )
break ;
2020-04-10 11:53:32 +02:00
if ( par )
break ;
par = true ;
}
2020-11-16 20:11:26 +01:00
if ( Token : : simpleMatch ( type , " decltype ( " ) & & type - > next ( ) - > valueType ( ) ) {
const ValueType * vt2 = type - > next ( ) - > valueType ( ) ;
if ( valuetype - > sign = = ValueType : : Sign : : UNKNOWN_SIGN )
valuetype - > sign = vt2 - > sign ;
if ( valuetype - > type = = ValueType : : Type : : UNKNOWN_TYPE )
valuetype - > type = vt2 - > type ;
valuetype - > constness + = vt2 - > constness ;
valuetype - > pointer + = vt2 - > pointer ;
2022-04-27 20:11:32 +02:00
valuetype - > reference = vt2 - > reference ;
2020-11-16 20:11:26 +01:00
type = type - > linkAt ( 1 ) - > next ( ) ;
continue ;
} else if ( type - > isSigned ( ) )
2015-10-04 20:32:16 +02:00
valuetype - > sign = ValueType : : Sign : : SIGNED ;
2015-10-04 23:27:58 +02:00
else if ( type - > isUnsigned ( ) )
2015-10-04 20:32:16 +02:00
valuetype - > sign = ValueType : : Sign : : UNSIGNED ;
2018-01-10 22:16:18 +01:00
if ( valuetype - > type = = ValueType : : Type : : UNKNOWN_TYPE & &
2018-01-12 08:19:21 +01:00
type - > type ( ) & & type - > type ( ) - > isTypeAlias ( ) & & type - > type ( ) - > typeStart & &
2019-09-01 11:36:02 +02:00
type - > type ( ) - > typeStart - > str ( ) ! = type - > str ( ) & & type - > type ( ) - > typeStart ! = previousType )
2022-08-21 17:11:22 +02:00
parsedecl ( type - > type ( ) - > typeStart , valuetype , defaultSignedness , settings , isCpp ) ;
2021-07-22 07:22:26 +02:00
else if ( Token : : Match ( type , " const|constexpr " ) )
2015-10-10 08:32:45 +02:00
valuetype - > constness | = ( 1 < < ( valuetype - > pointer - pointer0 ) ) ;
2021-04-30 16:47:02 +02:00
else if ( settings - > clang & & type - > str ( ) . size ( ) > 2 & & type - > str ( ) . find ( " :: " ) < type - > str ( ) . find ( " < " ) ) {
TokenList typeTokens ( settings ) ;
std : : string : : size_type pos1 = 0 ;
do {
2022-10-02 07:12:40 +02:00
const std : : string : : size_type pos2 = type - > str ( ) . find ( " :: " , pos1 ) ;
2021-04-30 16:47:02 +02:00
if ( pos2 = = std : : string : : npos ) {
typeTokens . addtoken ( type - > str ( ) . substr ( pos1 ) , 0 , 0 , 0 , false ) ;
break ;
}
typeTokens . addtoken ( type - > str ( ) . substr ( pos1 , pos2 - pos1 ) , 0 , 0 , 0 , false ) ;
typeTokens . addtoken ( " :: " , 0 , 0 , 0 , false ) ;
pos1 = pos2 + 2 ;
} while ( pos1 < type - > str ( ) . size ( ) ) ;
2022-04-07 06:47:15 +02:00
const Library : : Container * container =
settings - > library . detectContainerOrIterator ( typeTokens . front ( ) , & isIterator ) ;
2021-04-30 16:47:02 +02:00
if ( container ) {
2022-04-07 06:47:15 +02:00
if ( isIterator )
valuetype - > type = ValueType : : Type : : ITERATOR ;
else
valuetype - > type = ValueType : : Type : : CONTAINER ;
2021-04-30 16:47:02 +02:00
valuetype - > container = container ;
} else {
const Scope * scope = type - > scope ( ) ;
valuetype - > typeScope = scope - > check - > findScope ( typeTokens . front ( ) , scope ) ;
if ( valuetype - > typeScope )
valuetype - > type = ( scope - > type = = Scope : : ScopeType : : eClass ) ? ValueType : : Type : : RECORD : ValueType : : Type : : NONSTD ;
}
2022-08-21 17:11:22 +02:00
} else if ( const Library : : Container * container = ( isCpp ? settings - > library . detectContainerOrIterator ( type , & isIterator ) : nullptr ) ) {
2022-04-07 06:47:15 +02:00
if ( isIterator )
valuetype - > type = ValueType : : Type : : ITERATOR ;
else
valuetype - > type = ValueType : : Type : : CONTAINER ;
2017-04-06 07:07:20 +02:00
valuetype - > container = container ;
2022-04-01 23:26:44 +02:00
while ( Token : : Match ( type , " %type%|::|< " ) & & type - > str ( ) ! = " const " ) {
2018-04-06 22:26:35 +02:00
if ( type - > str ( ) = = " < " & & type - > link ( ) ) {
if ( container - > type_templateArgNo > = 0 ) {
const Token * templateType = type - > next ( ) ;
for ( int j = 0 ; templateType & & j < container - > type_templateArgNo ; j + + )
templateType = templateType - > nextTemplateArgument ( ) ;
valuetype - > containerTypeToken = templateType ;
}
2017-04-06 07:07:20 +02:00
type = type - > link ( ) ;
2018-04-06 22:26:35 +02:00
}
2017-04-06 07:07:20 +02:00
type = type - > next ( ) ;
}
2020-12-26 19:59:57 +01:00
if ( type & & type - > str ( ) = = " ( " & & type - > previous ( ) - > function ( ) )
2020-12-24 19:57:02 +01:00
// we are past the end of the type
type = type - > previous ( ) ;
2017-04-06 07:07:20 +02:00
continue ;
2022-08-21 17:11:22 +02:00
} else if ( const Library : : SmartPointer * smartPointer = ( isCpp ? settings - > library . detectSmartPointer ( type ) : nullptr ) ) {
2019-09-30 21:04:43 +02:00
const Token * argTok = Token : : findsimplematch ( type , " < " ) ;
if ( ! argTok )
2022-07-08 12:37:53 +02:00
break ;
2021-07-20 21:30:27 +02:00
valuetype - > smartPointer = smartPointer ;
2019-09-30 21:04:43 +02:00
valuetype - > smartPointerTypeToken = argTok - > next ( ) ;
valuetype - > smartPointerType = argTok - > next ( ) - > type ( ) ;
2021-08-14 19:00:58 +02:00
valuetype - > type = ValueType : : Type : : SMART_POINTER ;
2019-10-12 11:40:02 +02:00
type = argTok - > link ( ) ;
2020-04-19 20:08:47 +02:00
if ( type )
type = type - > next ( ) ;
2019-10-12 11:40:02 +02:00
continue ;
2017-04-06 07:07:20 +02:00
} else if ( Token : : Match ( type , " %name% :: %name% " ) ) {
std : : string typestr ;
const Token * end = type ;
while ( Token : : Match ( end , " %name% :: %name% " ) ) {
typestr + = end - > str ( ) + " :: " ;
end = end - > tokAt ( 2 ) ;
2017-03-05 01:21:02 +01:00
}
2017-04-06 07:07:20 +02:00
typestr + = end - > str ( ) ;
if ( valuetype - > fromLibraryType ( typestr , settings ) )
type = end ;
2020-10-04 20:02:19 +02:00
} else if ( ValueType : : Type : : UNKNOWN_TYPE ! = ValueType : : typeFromString ( type - > str ( ) , type - > isLong ( ) ) ) {
2022-10-02 07:12:40 +02:00
const ValueType : : Type t0 = valuetype - > type ;
2017-03-05 01:39:56 +01:00
valuetype - > type = ValueType : : typeFromString ( type - > str ( ) , type - > isLong ( ) ) ;
2020-10-04 20:02:19 +02:00
if ( t0 = = ValueType : : Type : : LONG ) {
if ( valuetype - > type = = ValueType : : Type : : LONG )
valuetype - > type = ValueType : : Type : : LONGLONG ;
else if ( valuetype - > type = = ValueType : : Type : : DOUBLE )
valuetype - > type = ValueType : : Type : : LONGDOUBLE ;
}
} else if ( type - > str ( ) = = " auto " ) {
2017-02-26 20:02:57 +01:00
const ValueType * vt = type - > valueType ( ) ;
2017-09-14 23:53:44 +02:00
if ( ! vt )
return nullptr ;
2017-02-26 20:02:57 +01:00
valuetype - > type = vt - > type ;
valuetype - > pointer = vt - > pointer ;
if ( vt - > sign ! = ValueType : : Sign : : UNKNOWN_SIGN )
valuetype - > sign = vt - > sign ;
2017-02-27 02:09:33 +01:00
valuetype - > constness = vt - > constness ;
2019-02-27 06:44:31 +01:00
valuetype - > originalTypeName = vt - > originalTypeName ;
2020-04-04 20:03:48 +02:00
while ( Token : : Match ( type , " %name%|*|&|:: " ) & & ! type - > variable ( ) ) {
if ( type - > str ( ) = = " * " )
valuetype - > pointer + + ;
if ( type - > str ( ) = = " const " )
valuetype - > constness | = ( 1 < < valuetype - > pointer ) ;
2017-02-27 02:09:33 +01:00
type = type - > next ( ) ;
2020-04-04 20:03:48 +02:00
}
2017-02-27 02:09:33 +01:00
break ;
2017-02-26 20:02:57 +01:00
} else if ( ! valuetype - > typeScope & & ( type - > str ( ) = = " struct " | | type - > str ( ) = = " enum " ) )
2017-03-05 14:53:32 +01:00
valuetype - > type = type - > str ( ) = = " struct " ? ValueType : : Type : : RECORD : ValueType : : Type : : NONSTD ;
2016-05-25 13:56:36 +02:00
else if ( ! valuetype - > typeScope & & type - > type ( ) & & type - > type ( ) - > classScope ) {
2020-05-15 20:58:33 +02:00
if ( type - > type ( ) - > classScope - > type = = Scope : : ScopeType : : eEnum ) {
valuetype - > type = ValueType : : Type : : INT ;
valuetype - > sign = ValueType : : Sign : : SIGNED ;
} else {
valuetype - > type = ValueType : : Type : : RECORD ;
}
2016-05-25 13:56:36 +02:00
valuetype - > typeScope = type - > type ( ) - > classScope ;
} else if ( type - > isName ( ) & & valuetype - > sign ! = ValueType : : Sign : : UNKNOWN_SIGN & & valuetype - > pointer = = 0U )
2016-01-05 19:47:11 +01:00
return nullptr ;
2015-10-04 20:32:16 +02:00
else if ( type - > str ( ) = = " * " )
valuetype - > pointer + + ;
2020-09-03 18:44:44 +02:00
else if ( type - > str ( ) = = " & " )
valuetype - > reference = Reference : : LValue ;
else if ( type - > str ( ) = = " && " )
valuetype - > reference = Reference : : RValue ;
2016-07-31 19:47:34 +02:00
else if ( type - > isStandardType ( ) )
valuetype - > fromLibraryType ( type - > str ( ) , settings ) ;
2018-06-20 14:49:55 +02:00
else if ( Token : : Match ( type - > previous ( ) , " !!:: %name% !!:: " ) )
valuetype - > fromLibraryType ( type - > str ( ) , settings ) ;
2015-10-07 20:24:17 +02:00
if ( ! type - > originalName ( ) . empty ( ) )
valuetype - > originalTypeName = type - > originalName ( ) ;
2015-10-04 20:32:16 +02:00
type = type - > next ( ) ;
}
2016-01-01 20:03:31 +01:00
2016-01-31 14:34:26 +01:00
// Set signedness for integral types..
if ( valuetype - > isIntegral ( ) & & valuetype - > sign = = ValueType : : Sign : : UNKNOWN_SIGN ) {
if ( valuetype - > type = = ValueType : : Type : : CHAR )
valuetype - > sign = defaultSignedness ;
else if ( valuetype - > type > = ValueType : : Type : : SHORT )
valuetype - > sign = ValueType : : Sign : : SIGNED ;
}
2016-01-01 20:03:31 +01:00
2020-09-03 18:44:44 +02:00
return ( type & & ( valuetype - > type ! = ValueType : : Type : : UNKNOWN_TYPE | | valuetype - > pointer > 0 | | valuetype - > reference ! = Reference : : None ) ) ? type : nullptr ;
2015-10-04 20:32:16 +02:00
}
2016-05-25 13:56:36 +02:00
static const Scope * getClassScope ( const Token * tok )
{
return tok & & tok - > valueType ( ) & & tok - > valueType ( ) - > typeScope & & tok - > valueType ( ) - > typeScope - > isClassOrStruct ( ) ?
tok - > valueType ( ) - > typeScope :
nullptr ;
}
static const Function * getOperatorFunction ( const Token * const tok )
{
const std : : string functionName ( " operator " + tok - > str ( ) ) ;
std : : multimap < std : : string , const Function * > : : const_iterator it ;
2018-04-04 21:51:31 +02:00
const Scope * classScope = getClassScope ( tok - > astOperand1 ( ) ) ;
2016-05-25 13:56:36 +02:00
if ( classScope ) {
it = classScope - > functionMap . find ( functionName ) ;
if ( it ! = classScope - > functionMap . end ( ) )
return it - > second ;
}
classScope = getClassScope ( tok - > astOperand2 ( ) ) ;
if ( classScope ) {
it = classScope - > functionMap . find ( functionName ) ;
if ( it ! = classScope - > functionMap . end ( ) )
return it - > second ;
}
return nullptr ;
}
2020-04-27 09:08:50 +02:00
void SymbolDatabase : : setValueTypeInTokenList ( bool reportDebugWarnings , Token * tokens )
2015-10-04 19:42:58 +02:00
{
2020-04-27 09:08:50 +02:00
if ( ! tokens )
tokens = const_cast < Tokenizer * > ( mTokenizer ) - > list . front ( ) ;
2016-01-01 17:33:59 +01:00
2015-10-04 19:42:58 +02:00
for ( Token * tok = tokens ; tok ; tok = tok - > next ( ) )
tok - > setValueType ( nullptr ) ;
for ( Token * tok = tokens ; tok ; tok = tok - > next ( ) ) {
if ( tok - > isNumber ( ) ) {
2015-10-07 18:10:48 +02:00
if ( MathLib : : isFloat ( tok - > str ( ) ) ) {
ValueType : : Type type = ValueType : : Type : : DOUBLE ;
2018-03-30 20:57:25 +02:00
const char suffix = tok - > str ( ) [ tok - > str ( ) . size ( ) - 1 ] ;
2016-01-03 13:34:47 +01:00
if ( suffix = = ' f ' | | suffix = = ' F ' )
2015-10-07 18:10:48 +02:00
type = ValueType : : Type : : FLOAT ;
2016-08-20 08:44:53 +02:00
else if ( suffix = = ' L ' | | suffix = = ' l ' )
type = ValueType : : Type : : LONGDOUBLE ;
2017-03-22 02:55:22 +01:00
setValueType ( tok , ValueType ( ValueType : : Sign : : UNKNOWN_SIGN , type , 0U ) ) ;
2015-10-07 18:10:48 +02:00
} else if ( MathLib : : isInt ( tok - > str ( ) ) ) {
2020-02-19 07:51:39 +01:00
const std : : string tokStr = MathLib : : abs ( tok - > str ( ) ) ;
const bool unsignedSuffix = ( tokStr . find_last_of ( " uU " ) ! = std : : string : : npos ) ;
2017-03-04 14:19:14 +01:00
ValueType : : Sign sign = unsignedSuffix ? ValueType : : Sign : : UNSIGNED : ValueType : : Sign : : SIGNED ;
2020-02-19 07:51:39 +01:00
ValueType : : Type type = ValueType : : Type : : INT ;
const MathLib : : biguint value = MathLib : : toULongNumber ( tokStr ) ;
for ( std : : size_t pos = tokStr . size ( ) - 1U ; pos > 0U ; - - pos ) {
const char suffix = tokStr [ pos ] ;
2016-01-03 13:34:47 +01:00
if ( suffix = = ' u ' | | suffix = = ' U ' )
sign = ValueType : : Sign : : UNSIGNED ;
2016-07-26 13:19:28 +02:00
else if ( suffix = = ' l ' | | suffix = = ' L ' )
2016-01-03 13:34:47 +01:00
type = ( type = = ValueType : : Type : : INT ) ? ValueType : : Type : : LONG : ValueType : : Type : : LONGLONG ;
2020-02-19 07:51:39 +01:00
else if ( pos > 2U & & suffix = = ' 4 ' & & tokStr [ pos - 1 ] = = ' 6 ' & & tokStr [ pos - 2 ] = = ' i ' ) {
2016-07-26 13:19:28 +02:00
type = ValueType : : Type : : LONGLONG ;
pos - = 2 ;
} else break ;
2015-10-07 18:10:48 +02:00
}
2020-02-19 07:51:39 +01:00
if ( mSettings - > platformType ! = cppcheck : : Platform : : Unspecified ) {
if ( type < = ValueType : : Type : : INT & & mSettings - > isIntValue ( unsignedSuffix ? ( value > > 1 ) : value ) )
type = ValueType : : Type : : INT ;
else if ( type < = ValueType : : Type : : INT & & ! MathLib : : isDec ( tokStr ) & & mSettings - > isIntValue ( value > > 2 ) ) {
type = ValueType : : Type : : INT ;
sign = ValueType : : Sign : : UNSIGNED ;
} else if ( type < = ValueType : : Type : : LONG & & mSettings - > isLongValue ( unsignedSuffix ? ( value > > 1 ) : value ) )
type = ValueType : : Type : : LONG ;
else if ( type < = ValueType : : Type : : LONG & & ! MathLib : : isDec ( tokStr ) & & mSettings - > isLongValue ( value > > 2 ) ) {
type = ValueType : : Type : : LONG ;
sign = ValueType : : Sign : : UNSIGNED ;
} else if ( mSettings - > isLongLongValue ( unsignedSuffix ? ( value > > 1 ) : value ) )
type = ValueType : : Type : : LONGLONG ;
else {
type = ValueType : : Type : : LONGLONG ;
sign = ValueType : : Sign : : UNSIGNED ;
}
}
2017-03-22 02:55:22 +01:00
setValueType ( tok , ValueType ( sign , type , 0U ) ) ;
2015-10-07 18:10:48 +02:00
}
2016-05-25 13:56:36 +02:00
} else if ( tok - > isComparisonOp ( ) | | tok - > tokType ( ) = = Token : : eLogicalOp ) {
2018-06-16 23:30:00 +02:00
if ( mIsCpp & & tok - > isComparisonOp ( ) & & ( getClassScope ( tok - > astOperand1 ( ) ) | | getClassScope ( tok - > astOperand2 ( ) ) ) ) {
2016-05-25 13:56:36 +02:00
const Function * function = getOperatorFunction ( tok ) ;
if ( function ) {
ValueType vt ;
2022-08-21 17:11:22 +02:00
parsedecl ( function - > retDef , & vt , mDefaultSignedness , mSettings , mIsCpp ) ;
2017-03-22 02:55:22 +01:00
setValueType ( tok , vt ) ;
2016-05-25 13:56:36 +02:00
continue ;
}
}
2017-03-22 02:55:22 +01:00
setValueType ( tok , ValueType ( ValueType : : Sign : : UNKNOWN_SIGN , ValueType : : Type : : BOOL , 0U ) ) ;
2019-03-09 17:27:27 +01:00
} else if ( tok - > isBoolean ( ) ) {
setValueType ( tok , ValueType ( ValueType : : Sign : : UNKNOWN_SIGN , ValueType : : Type : : BOOL , 0U ) ) ;
Set correct type and size of string and char literals (#2275)
* Set correct type and size of string and char literals
Use that string and char literal tokens store the prefix. This makes
it possible to distinghuish between different type of string literals
(i.e., utf8 encoded strings, utf16, wide strings, etc) which have
different type.
When the tokens holding the string and character values have the correct
type, it is possible to improve Token::getStrSize() to give the correct
result for all string types. Previously, it would return the number of
characters in the string, i.e., it would give the wrong size unless
the type of the string was char*.
Since strings now can have different size (in number of bytes) and
length (in number of elements), add a new helper function that returns
the number of characters. Checkers have been updated to use the correct
functions.
Having the size makes it possible to find more problems with prefixed
strings, and to reduce false positives, for example in the buffer
overflow checker.
Also, improve the stringLiteralWrite error message to also print the
prefix of the string (if there is one).
* Add comment and update string length
2019-10-20 07:11:57 +02:00
} else if ( tok - > tokType ( ) = = Token : : eChar | | tok - > tokType ( ) = = Token : : eString ) {
2022-10-02 07:12:40 +02:00
nonneg int const pointer = tok - > tokType ( ) = = Token : : eChar ? 0U : 1U ;
nonneg int const constness = tok - > tokType ( ) = = Token : : eChar ? 0U : 1U ;
Set correct type and size of string and char literals (#2275)
* Set correct type and size of string and char literals
Use that string and char literal tokens store the prefix. This makes
it possible to distinghuish between different type of string literals
(i.e., utf8 encoded strings, utf16, wide strings, etc) which have
different type.
When the tokens holding the string and character values have the correct
type, it is possible to improve Token::getStrSize() to give the correct
result for all string types. Previously, it would return the number of
characters in the string, i.e., it would give the wrong size unless
the type of the string was char*.
Since strings now can have different size (in number of bytes) and
length (in number of elements), add a new helper function that returns
the number of characters. Checkers have been updated to use the correct
functions.
Having the size makes it possible to find more problems with prefixed
strings, and to reduce false positives, for example in the buffer
overflow checker.
Also, improve the stringLiteralWrite error message to also print the
prefix of the string (if there is one).
* Add comment and update string length
2019-10-20 07:11:57 +02:00
ValueType valuetype ( ValueType : : Sign : : UNKNOWN_SIGN , ValueType : : Type : : CHAR , pointer , constness ) ;
if ( mIsCpp & & mSettings - > standards . cpp > = Standards : : CPP20 & & tok - > isUtf8 ( ) ) {
valuetype . originalTypeName = " char8_t " ;
valuetype . fromLibraryType ( valuetype . originalTypeName , mSettings ) ;
} else if ( tok - > isUtf16 ( ) ) {
valuetype . originalTypeName = " char16_t " ;
valuetype . fromLibraryType ( valuetype . originalTypeName , mSettings ) ;
} else if ( tok - > isUtf32 ( ) ) {
valuetype . originalTypeName = " char32_t " ;
valuetype . fromLibraryType ( valuetype . originalTypeName , mSettings ) ;
} else if ( tok - > isLong ( ) ) {
2015-10-11 08:13:30 +02:00
valuetype . originalTypeName = " wchar_t " ;
2019-05-01 16:34:28 +02:00
valuetype . type = ValueType : : Type : : WCHAR_T ;
Set correct type and size of string and char literals (#2275)
* Set correct type and size of string and char literals
Use that string and char literal tokens store the prefix. This makes
it possible to distinghuish between different type of string literals
(i.e., utf8 encoded strings, utf16, wide strings, etc) which have
different type.
When the tokens holding the string and character values have the correct
type, it is possible to improve Token::getStrSize() to give the correct
result for all string types. Previously, it would return the number of
characters in the string, i.e., it would give the wrong size unless
the type of the string was char*.
Since strings now can have different size (in number of bytes) and
length (in number of elements), add a new helper function that returns
the number of characters. Checkers have been updated to use the correct
functions.
Having the size makes it possible to find more problems with prefixed
strings, and to reduce false positives, for example in the buffer
overflow checker.
Also, improve the stringLiteralWrite error message to also print the
prefix of the string (if there is one).
* Add comment and update string length
2019-10-20 07:11:57 +02:00
} else if ( ( tok - > tokType ( ) = = Token : : eChar ) & & ( ( tok - > isCChar ( ) & & ! mIsCpp ) | | ( tok - > isCMultiChar ( ) ) ) ) {
valuetype . type = ValueType : : Type : : INT ;
valuetype . sign = ValueType : : Sign : : SIGNED ;
2015-10-11 08:13:30 +02:00
}
2017-03-22 02:55:22 +01:00
setValueType ( tok , valuetype ) ;
2020-09-09 04:54:38 +02:00
} else if ( tok - > link ( ) & & Token : : Match ( tok , " (| { " )) {
const Token * start = tok - > astOperand1 ( ) ? tok - > astOperand1 ( ) - > findExpressionStartEndTokens ( ) . first : nullptr ;
2015-10-04 19:42:58 +02:00
// cast
2019-02-23 17:29:53 +01:00
if ( tok - > isCast ( ) & & ! tok - > astOperand2 ( ) & & Token : : Match ( tok , " ( %name% " ) ) {
2015-10-04 20:32:16 +02:00
ValueType valuetype ;
2022-08-21 17:11:22 +02:00
if ( Token : : simpleMatch ( parsedecl ( tok - > next ( ) , & valuetype , mDefaultSignedness , mSettings , mIsCpp ) , " ) " ) )
2017-03-22 02:55:22 +01:00
setValueType ( tok , valuetype ) ;
2015-10-04 19:42:58 +02:00
}
2015-10-11 08:42:31 +02:00
2015-12-26 15:20:17 +01:00
// C++ cast
2019-02-23 17:29:53 +01:00
else if ( tok - > astOperand2 ( ) & & Token : : Match ( tok - > astOperand1 ( ) , " static_cast|const_cast|dynamic_cast|reinterpret_cast < %name% " ) & & tok - > astOperand1 ( ) - > linkAt ( 1 ) ) {
2015-12-26 15:20:17 +01:00
ValueType valuetype ;
2022-08-21 17:11:22 +02:00
if ( Token : : simpleMatch ( parsedecl ( tok - > astOperand1 ( ) - > tokAt ( 2 ) , & valuetype , mDefaultSignedness , mSettings , mIsCpp ) , " > " ) )
2017-03-22 02:55:22 +01:00
setValueType ( tok , valuetype ) ;
2015-12-26 15:20:17 +01:00
}
2020-09-09 04:54:38 +02:00
// Construct smart pointer
else if ( mSettings - > library . isSmartPointer ( start ) ) {
ValueType valuetype ;
2022-08-21 17:11:22 +02:00
if ( parsedecl ( start , & valuetype , mDefaultSignedness , mSettings , mIsCpp ) ) {
2020-09-09 04:54:38 +02:00
setValueType ( tok , valuetype ) ;
setValueType ( tok - > astOperand1 ( ) , valuetype ) ;
}
}
2015-10-11 08:42:31 +02:00
// function
2015-10-11 12:20:40 +02:00
else if ( tok - > previous ( ) & & tok - > previous ( ) - > function ( ) & & tok - > previous ( ) - > function ( ) - > retDef ) {
2015-10-11 08:42:31 +02:00
ValueType valuetype ;
2022-08-21 17:11:22 +02:00
if ( parsedecl ( tok - > previous ( ) - > function ( ) - > retDef , & valuetype , mDefaultSignedness , mSettings , mIsCpp ) )
2017-03-22 02:55:22 +01:00
setValueType ( tok , valuetype ) ;
2015-10-11 08:42:31 +02:00
}
2015-10-11 12:20:40 +02:00
else if ( Token : : simpleMatch ( tok - > previous ( ) , " sizeof ( " ) ) {
ValueType valuetype ( ValueType : : Sign : : UNSIGNED , ValueType : : Type : : LONG , 0U ) ;
2022-01-27 19:43:52 +01:00
if ( mSettings - > platformType = = cppcheck : : Platform : : Win64 )
valuetype . type = ValueType : : Type : : LONGLONG ;
2015-10-11 12:20:40 +02:00
valuetype . originalTypeName = " size_t " ;
2017-03-22 02:55:22 +01:00
setValueType ( tok , valuetype ) ;
2016-07-20 09:39:48 +02:00
if ( Token : : Match ( tok , " ( %type% %type%| *| *| ) " ) ) {
ValueType vt ;
2022-08-21 17:11:22 +02:00
if ( parsedecl ( tok - > next ( ) , & vt , mDefaultSignedness , mSettings , mIsCpp ) ) {
2017-03-22 02:55:22 +01:00
setValueType ( tok - > next ( ) , vt ) ;
2016-07-20 09:39:48 +02:00
}
}
2015-10-11 12:20:40 +02:00
}
2016-10-23 23:20:36 +02:00
2018-05-20 22:58:05 +02:00
// function style cast
else if ( tok - > previous ( ) & & tok - > previous ( ) - > isStandardType ( ) ) {
ValueType valuetype ;
2019-10-08 17:53:29 +02:00
if ( tok - > astOperand1 ( ) & & valuetype . fromLibraryType ( tok - > astOperand1 ( ) - > expressionString ( ) , mSettings ) ) {
2019-10-08 11:24:54 +02:00
setValueType ( tok , valuetype ) ;
continue ;
}
2018-05-20 22:58:05 +02:00
valuetype . type = ValueType : : typeFromString ( tok - > previous ( ) - > str ( ) , tok - > previous ( ) - > isLong ( ) ) ;
2019-02-23 17:29:53 +01:00
if ( tok - > previous ( ) - > isUnsigned ( ) )
valuetype . sign = ValueType : : Sign : : UNSIGNED ;
else if ( tok - > previous ( ) - > isSigned ( ) )
valuetype . sign = ValueType : : Sign : : SIGNED ;
2021-11-07 18:19:56 +01:00
else if ( valuetype . isIntegral ( ) & & valuetype . type ! = ValueType : : UNKNOWN_INT )
valuetype . sign = mDefaultSignedness ;
2018-05-20 22:58:05 +02:00
setValueType ( tok , valuetype ) ;
}
2019-10-14 09:19:16 +02:00
// constructor call
else if ( tok - > previous ( ) & & tok - > previous ( ) - > function ( ) & & tok - > previous ( ) - > function ( ) - > isConstructor ( ) ) {
2018-05-22 06:42:37 +02:00
ValueType valuetype ;
valuetype . type = ValueType : : RECORD ;
2019-10-14 09:19:16 +02:00
valuetype . typeScope = tok - > previous ( ) - > function ( ) - > token - > scope ( ) ;
2018-05-22 06:42:37 +02:00
setValueType ( tok , valuetype ) ;
}
2021-11-15 20:36:38 +01:00
else if ( Token : : simpleMatch ( tok - > previous ( ) , " = { " ) && tok->tokAt(-2) && tok->tokAt(-2)->valueType()) {
ValueType vt = * tok - > tokAt ( - 2 ) - > valueType ( ) ;
setValueType ( tok , vt ) ;
}
2019-10-08 11:24:54 +02:00
// library type/function
2016-10-23 23:20:36 +02:00
else if ( tok - > previous ( ) ) {
2021-12-04 17:00:55 +01:00
// Aggregate constructor
if ( Token : : Match ( tok - > previous ( ) , " %name% " ) ) {
ValueType valuetype ;
2022-08-21 17:11:22 +02:00
if ( parsedecl ( tok - > previous ( ) , & valuetype , mDefaultSignedness , mSettings , mIsCpp ) ) {
2021-12-04 17:00:55 +01:00
if ( valuetype . typeScope ) {
setValueType ( tok , valuetype ) ;
continue ;
}
}
}
2019-10-08 11:24:54 +02:00
if ( tok - > astParent ( ) & & Token : : Match ( tok - > astOperand1 ( ) , " %name%|:: " ) ) {
2019-10-23 19:54:59 +02:00
const Token * typeStartToken = tok - > astOperand1 ( ) ;
while ( typeStartToken & & typeStartToken - > str ( ) = = " :: " )
typeStartToken = typeStartToken - > astOperand1 ( ) ;
2022-04-07 06:47:15 +02:00
if ( mSettings - > library . detectContainerOrIterator ( typeStartToken ) | |
2021-11-26 13:38:40 +01:00
mSettings - > library . detectSmartPointer ( typeStartToken ) ) {
2019-10-08 11:24:54 +02:00
ValueType vt ;
2022-08-21 17:11:22 +02:00
if ( parsedecl ( typeStartToken , & vt , mDefaultSignedness , mSettings , mIsCpp ) ) {
2021-11-26 13:38:40 +01:00
setValueType ( tok , vt ) ;
continue ;
}
2021-08-14 19:00:58 +02:00
}
2019-10-08 12:51:23 +02:00
const std : : string e = tok - > astOperand1 ( ) - > expressionString ( ) ;
if ( ( e = = " std::make_shared " | | e = = " std::make_unique " ) & & Token : : Match ( tok - > astOperand1 ( ) , " :: %name% < %name% " ) ) {
ValueType vt ;
2022-08-21 17:11:22 +02:00
parsedecl ( tok - > astOperand1 ( ) - > tokAt ( 3 ) , & vt , mDefaultSignedness , mSettings , mIsCpp ) ;
2019-10-08 12:51:23 +02:00
if ( vt . typeScope ) {
vt . smartPointerType = vt . typeScope - > definedType ;
vt . typeScope = nullptr ;
}
2021-08-14 19:00:58 +02:00
if ( e = = " std::make_shared " & & mSettings - > library . smartPointers . count ( " std::shared_ptr " ) > 0 )
vt . smartPointer = & mSettings - > library . smartPointers . at ( " std::shared_ptr " ) ;
if ( e = = " std::make_unique " & & mSettings - > library . smartPointers . count ( " std::unique_ptr " ) > 0 )
vt . smartPointer = & mSettings - > library . smartPointers . at ( " std::unique_ptr " ) ;
vt . type = ValueType : : Type : : SMART_POINTER ;
vt . smartPointerTypeToken = tok - > astOperand1 ( ) - > tokAt ( 3 ) ;
setValueType ( tok , vt ) ;
continue ;
2019-10-08 12:51:23 +02:00
}
2019-10-22 20:40:36 +02:00
ValueType podtype ;
if ( podtype . fromLibraryType ( e , mSettings ) ) {
setValueType ( tok , podtype ) ;
continue ;
}
2019-10-08 11:24:54 +02:00
}
2018-06-16 16:10:28 +02:00
const std : : string & typestr ( mSettings - > library . returnValueType ( tok - > previous ( ) ) ) ;
2019-09-28 14:57:24 +02:00
if ( ! typestr . empty ( ) ) {
ValueType valuetype ;
2020-09-02 07:13:15 +02:00
TokenList tokenList ( mSettings ) ;
std : : istringstream istr ( typestr + " ; " ) ;
tokenList . createTokens ( istr ) ;
2020-10-16 07:56:31 +02:00
tokenList . simplifyStdType ( ) ;
2022-08-21 17:11:22 +02:00
if ( parsedecl ( tokenList . front ( ) , & valuetype , mDefaultSignedness , mSettings , mIsCpp ) ) {
2020-09-02 07:13:15 +02:00
valuetype . originalTypeName = typestr ;
2019-09-28 14:57:24 +02:00
setValueType ( tok , valuetype ) ;
}
}
2017-03-05 14:53:32 +01:00
if ( typestr . empty ( ) | | typestr = = " iterator " ) {
if ( Token : : simpleMatch ( tok - > astOperand1 ( ) , " . " ) & &
tok - > astOperand1 ( ) - > astOperand1 ( ) & &
tok - > astOperand1 ( ) - > astOperand2 ( ) & &
tok - > astOperand1 ( ) - > astOperand1 ( ) - > valueType ( ) & &
tok - > astOperand1 ( ) - > astOperand1 ( ) - > valueType ( ) - > container ) {
const Library : : Container * cont = tok - > astOperand1 ( ) - > astOperand1 ( ) - > valueType ( ) - > container ;
2018-04-04 21:51:31 +02:00
const std : : map < std : : string , Library : : Container : : Function > : : const_iterator it = cont - > functions . find ( tok - > astOperand1 ( ) - > astOperand2 ( ) - > str ( ) ) ;
2017-03-05 14:53:32 +01:00
if ( it ! = cont - > functions . end ( ) ) {
if ( it - > second . yield = = Library : : Container : : Yield : : START_ITERATOR | |
it - > second . yield = = Library : : Container : : Yield : : END_ITERATOR | |
it - > second . yield = = Library : : Container : : Yield : : ITERATOR ) {
ValueType vt ;
vt . type = ValueType : : Type : : ITERATOR ;
vt . container = cont ;
2021-08-14 19:00:58 +02:00
vt . containerTypeToken =
tok - > astOperand1 ( ) - > astOperand1 ( ) - > valueType ( ) - > containerTypeToken ;
2017-03-22 02:55:22 +01:00
setValueType ( tok , vt ) ;
2017-03-05 14:53:32 +01:00
}
}
}
2016-10-23 23:20:36 +02:00
continue ;
2017-03-05 14:53:32 +01:00
}
2018-06-16 16:10:28 +02:00
TokenList tokenList ( mSettings ) ;
2016-10-23 23:20:36 +02:00
std : : istringstream istr ( typestr + " ; " ) ;
if ( tokenList . createTokens ( istr ) ) {
ValueType vt ;
2019-02-15 13:29:52 +01:00
tokenList . simplifyPlatformTypes ( ) ;
2017-10-03 22:10:13 +02:00
tokenList . simplifyStdType ( ) ;
2022-08-21 17:11:22 +02:00
if ( parsedecl ( tokenList . front ( ) , & vt , mDefaultSignedness , mSettings , mIsCpp ) ) {
2020-09-02 07:13:15 +02:00
vt . originalTypeName = typestr ;
2017-03-22 02:55:22 +01:00
setValueType ( tok , vt ) ;
2016-10-23 23:20:36 +02:00
}
}
}
2020-06-10 21:13:53 +02:00
} else if ( tok - > str ( ) = = " return " ) {
const Scope * functionScope = tok - > scope ( ) ;
while ( functionScope & & functionScope - > isExecutable ( ) & & functionScope - > type ! = Scope : : eLambda & & functionScope - > type ! = Scope : : eFunction )
functionScope = functionScope - > nestedIn ;
2021-10-30 09:06:36 +02:00
if ( functionScope & & functionScope - > type = = Scope : : eFunction & & functionScope - > function & &
functionScope - > function - > retDef ) {
2022-08-21 17:11:22 +02:00
ValueType vt = ValueType : : parseDecl ( functionScope - > function - > retDef , mSettings , mIsCpp ) ;
2021-10-30 09:06:36 +02:00
setValueType ( tok , vt ) ;
if ( Token : : simpleMatch ( tok , " return { " ) )
setValueType ( tok - > next ( ) , vt ) ;
}
2015-10-04 19:42:58 +02:00
} else if ( tok - > variable ( ) ) {
2017-03-22 02:55:22 +01:00
setValueType ( tok , * tok - > variable ( ) ) ;
2020-11-16 20:11:26 +01:00
if ( ! tok - > variable ( ) - > valueType ( ) & & tok - > valueType ( ) )
const_cast < Variable * > ( tok - > variable ( ) ) - > setValueType ( * tok - > valueType ( ) ) ;
2016-04-22 06:02:54 +02:00
} else if ( tok - > enumerator ( ) ) {
2017-03-22 02:55:22 +01:00
setValueType ( tok , * tok - > enumerator ( ) ) ;
2020-05-17 17:32:31 +02:00
} else if ( tok - > isKeyword ( ) & & tok - > str ( ) = = " new " ) {
2017-03-05 10:02:47 +01:00
const Token * typeTok = tok - > next ( ) ;
if ( Token : : Match ( typeTok , " ( std| ::| nothrow ) " ) )
typeTok = typeTok - > link ( ) - > next ( ) ;
2022-04-07 06:47:15 +02:00
bool isIterator = false ;
if ( const Library : : Container * c = mSettings - > library . detectContainerOrIterator ( typeTok , & isIterator ) ) {
2017-04-05 22:05:29 +02:00
ValueType vt ;
vt . pointer = 1 ;
vt . container = c ;
2022-04-07 06:47:15 +02:00
vt . type = isIterator ? ValueType : : Type : : ITERATOR : ValueType : : Type : : CONTAINER ;
2017-04-05 22:05:29 +02:00
setValueType ( tok , vt ) ;
continue ;
}
2017-03-05 10:24:51 +01:00
std : : string typestr ;
while ( Token : : Match ( typeTok , " %name% :: %name% " ) ) {
typestr + = typeTok - > str ( ) + " :: " ;
typeTok = typeTok - > tokAt ( 2 ) ;
}
2017-03-05 10:02:47 +01:00
if ( ! Token : : Match ( typeTok , " %type% ;|[|( " ) )
2017-04-01 22:22:37 +02:00
continue ;
2017-03-05 10:24:51 +01:00
typestr + = typeTok - > str ( ) ;
2017-03-05 10:02:47 +01:00
ValueType vt ;
vt . pointer = 1 ;
if ( typeTok - > type ( ) & & typeTok - > type ( ) - > classScope ) {
2017-03-05 14:53:32 +01:00
vt . type = ValueType : : Type : : RECORD ;
2017-03-05 10:02:47 +01:00
vt . typeScope = typeTok - > type ( ) - > classScope ;
} else {
2017-03-05 10:24:51 +01:00
vt . type = ValueType : : typeFromString ( typestr , typeTok - > isLong ( ) ) ;
2017-03-02 22:24:26 +01:00
if ( vt . type = = ValueType : : Type : : UNKNOWN_TYPE )
2018-06-16 16:10:28 +02:00
vt . fromLibraryType ( typestr , mSettings ) ;
2017-03-05 10:02:47 +01:00
if ( vt . type = = ValueType : : Type : : UNKNOWN_TYPE )
2017-04-01 22:22:37 +02:00
continue ;
2017-02-27 20:57:28 +01:00
if ( typeTok - > isUnsigned ( ) )
vt . sign = ValueType : : Sign : : UNSIGNED ;
else if ( typeTok - > isSigned ( ) )
vt . sign = ValueType : : Sign : : SIGNED ;
if ( vt . sign = = ValueType : : Sign : : UNKNOWN_SIGN & & vt . isIntegral ( ) )
2018-06-16 23:25:35 +02:00
vt . sign = ( vt . type = = ValueType : : Type : : CHAR ) ? mDefaultSignedness : ValueType : : Sign : : SIGNED ;
2017-02-27 20:57:28 +01:00
}
2017-03-22 02:55:22 +01:00
setValueType ( tok , vt ) ;
2020-11-07 18:12:47 +01:00
if ( Token : : simpleMatch ( tok - > astOperand1 ( ) , " ( " ) ) {
vt . pointer - - ;
setValueType ( tok - > astOperand1 ( ) , vt ) ;
}
2020-05-17 17:32:31 +02:00
} else if ( tok - > isKeyword ( ) & & tok - > str ( ) = = " return " & & tok - > scope ( ) ) {
2019-10-12 11:40:02 +02:00
const Scope * fscope = tok - > scope ( ) ;
while ( fscope & & ! fscope - > function )
fscope = fscope - > nestedIn ;
if ( fscope & & fscope - > function & & fscope - > function - > retDef ) {
2019-03-19 06:25:10 +01:00
ValueType vt ;
2022-08-21 17:11:22 +02:00
parsedecl ( fscope - > function - > retDef , & vt , mDefaultSignedness , mSettings , mIsCpp ) ;
2019-03-19 06:25:10 +01:00
setValueType ( tok , vt ) ;
}
2015-10-04 19:42:58 +02:00
}
}
2017-03-23 03:09:40 +01:00
2019-08-05 13:42:00 +02:00
if ( reportDebugWarnings & & mSettings - > debugwarnings ) {
2019-03-31 17:38:00 +02:00
for ( Token * tok = tokens ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " auto " & & ! tok - > valueType ( ) )
2021-04-16 15:19:29 +02:00
debugMessage ( tok , " autoNoType " , " auto token with no type. " ) ;
2019-03-31 17:38:00 +02:00
}
}
2017-03-24 12:19:14 +01:00
// Update functions with new type information.
createSymbolDatabaseSetFunctionPointers ( false ) ;
2017-03-23 03:09:40 +01:00
// Update auto variables with new type information.
createSymbolDatabaseSetVariablePointers ( ) ;
2015-10-04 19:42:58 +02:00
}
2015-10-07 13:38:34 +02:00
2022-08-21 17:11:22 +02:00
ValueType ValueType : : parseDecl ( const Token * type , const Settings * settings , bool isCpp )
2016-12-18 14:03:48 +01:00
{
ValueType vt ;
2022-08-21 17:11:22 +02:00
parsedecl ( type , & vt , settings - > defaultSign = = ' u ' ? Sign : : UNSIGNED : Sign : : SIGNED , settings , isCpp ) ;
2016-12-18 14:03:48 +01:00
return vt ;
}
2017-03-01 18:09:50 +01:00
ValueType : : Type ValueType : : typeFromString ( const std : : string & typestr , bool longType )
{
if ( typestr = = " void " )
return ValueType : : Type : : VOID ;
2017-03-04 11:13:28 +01:00
if ( typestr = = " bool " | | typestr = = " _Bool " )
2017-03-01 18:09:50 +01:00
return ValueType : : Type : : BOOL ;
if ( typestr = = " char " )
return ValueType : : Type : : CHAR ;
if ( typestr = = " short " )
return ValueType : : Type : : SHORT ;
2019-05-01 16:34:28 +02:00
if ( typestr = = " wchar_t " )
return ValueType : : Type : : WCHAR_T ;
2017-03-01 18:09:50 +01:00
if ( typestr = = " int " )
return ValueType : : Type : : INT ;
if ( typestr = = " long " )
return longType ? ValueType : : Type : : LONGLONG : ValueType : : Type : : LONG ;
if ( typestr = = " float " )
return ValueType : : Type : : FLOAT ;
if ( typestr = = " double " )
return longType ? ValueType : : Type : : LONGDOUBLE : ValueType : : Type : : DOUBLE ;
return ValueType : : Type : : UNKNOWN_TYPE ;
}
2016-07-31 19:47:34 +02:00
bool ValueType : : fromLibraryType ( const std : : string & typestr , const Settings * settings )
{
const Library : : PodType * podtype = settings - > library . podtype ( typestr ) ;
if ( podtype & & ( podtype - > sign = = ' s ' | | podtype - > sign = = ' u ' ) ) {
if ( podtype - > size = = 1 )
type = ValueType : : Type : : CHAR ;
else if ( podtype - > size = = settings - > sizeof_int )
type = ValueType : : Type : : INT ;
else if ( podtype - > size = = settings - > sizeof_short )
type = ValueType : : Type : : SHORT ;
else if ( podtype - > size = = settings - > sizeof_long )
type = ValueType : : Type : : LONG ;
else if ( podtype - > size = = settings - > sizeof_long_long )
type = ValueType : : Type : : LONGLONG ;
2021-01-08 10:29:01 +01:00
else if ( podtype - > stdtype = = Library : : PodType : : Type : : BOOL )
2019-09-29 16:48:25 +02:00
type = ValueType : : Type : : BOOL ;
2021-01-08 10:29:01 +01:00
else if ( podtype - > stdtype = = Library : : PodType : : Type : : CHAR )
2019-09-29 16:48:25 +02:00
type = ValueType : : Type : : CHAR ;
2021-01-08 10:29:01 +01:00
else if ( podtype - > stdtype = = Library : : PodType : : Type : : SHORT )
2019-09-29 16:48:25 +02:00
type = ValueType : : Type : : SHORT ;
2021-01-08 10:29:01 +01:00
else if ( podtype - > stdtype = = Library : : PodType : : Type : : INT )
2019-09-29 16:48:25 +02:00
type = ValueType : : Type : : INT ;
2021-01-08 10:29:01 +01:00
else if ( podtype - > stdtype = = Library : : PodType : : Type : : LONG )
2019-09-29 16:48:25 +02:00
type = ValueType : : Type : : LONG ;
2021-01-08 10:29:01 +01:00
else if ( podtype - > stdtype = = Library : : PodType : : Type : : LONGLONG )
2019-09-29 16:48:25 +02:00
type = ValueType : : Type : : LONGLONG ;
2016-07-31 19:47:34 +02:00
else
type = ValueType : : Type : : UNKNOWN_INT ;
sign = ( podtype - > sign = = ' u ' ) ? ValueType : : UNSIGNED : ValueType : : SIGNED ;
return true ;
2022-03-24 06:35:44 +01:00
} else if ( podtype & & podtype - > stdtype = = Library : : PodType : : Type : : NO ) {
type = ValueType : : Type : : POD ;
sign = ValueType : : UNKNOWN_SIGN ;
return true ;
2016-07-31 19:47:34 +02:00
}
const Library : : PlatformType * platformType = settings - > library . platform_type ( typestr , settings - > platformString ( ) ) ;
if ( platformType ) {
2018-06-16 20:25:54 +02:00
if ( platformType - > mType = = " char " )
2016-07-31 19:47:34 +02:00
type = ValueType : : Type : : CHAR ;
2018-06-16 20:25:54 +02:00
else if ( platformType - > mType = = " short " )
2016-07-31 19:47:34 +02:00
type = ValueType : : Type : : SHORT ;
2019-05-01 16:34:28 +02:00
else if ( platformType - > mType = = " wchar_t " )
type = ValueType : : Type : : WCHAR_T ;
2018-06-16 20:25:54 +02:00
else if ( platformType - > mType = = " int " )
2019-11-20 15:37:09 +01:00
type = platformType - > mLong ? ValueType : : Type : : LONG : ValueType : : Type : : INT ;
2018-06-16 20:25:54 +02:00
else if ( platformType - > mType = = " long " )
2019-11-20 15:37:09 +01:00
type = platformType - > mLong ? ValueType : : Type : : LONGLONG : ValueType : : Type : : LONG ;
if ( platformType - > mSigned )
2016-07-31 19:47:34 +02:00
sign = ValueType : : SIGNED ;
2019-11-20 15:37:09 +01:00
else if ( platformType - > mUnsigned )
2016-07-31 19:47:34 +02:00
sign = ValueType : : UNSIGNED ;
2019-11-20 15:37:09 +01:00
if ( platformType - > mPointer )
2016-07-31 19:47:34 +02:00
pointer = 1 ;
2019-11-20 15:37:09 +01:00
if ( platformType - > mPtrPtr )
2016-07-31 19:47:34 +02:00
pointer = 2 ;
2019-11-20 15:37:09 +01:00
if ( platformType - > mConstPtr )
2016-07-31 19:47:34 +02:00
constness = 1 ;
return true ;
2017-03-05 18:19:49 +01:00
} else if ( ! podtype & & ( typestr = = " size_t " | | typestr = = " std::size_t " ) ) {
originalTypeName = " size_t " ;
sign = ValueType : : UNSIGNED ;
if ( settings - > sizeof_size_t = = settings - > sizeof_long )
type = ValueType : : Type : : LONG ;
else if ( settings - > sizeof_size_t = = settings - > sizeof_long_long )
type = ValueType : : Type : : LONGLONG ;
else if ( settings - > sizeof_size_t = = settings - > sizeof_int )
type = ValueType : : Type : : INT ;
else
type = ValueType : : Type : : UNKNOWN_INT ;
return true ;
2016-07-31 19:47:34 +02:00
}
return false ;
}
2017-04-16 09:11:20 +02:00
std : : string ValueType : : dump ( ) const
{
std : : ostringstream ret ;
switch ( type ) {
case UNKNOWN_TYPE :
return " " ;
case NONSTD :
ret < < " valueType-type= \" nonstd \" " ;
break ;
2022-03-30 19:30:02 +02:00
case POD :
ret < < " valueType-type= \" pod \" " ;
break ;
2017-04-16 09:11:20 +02:00
case RECORD :
ret < < " valueType-type= \" record \" " ;
break ;
2021-08-14 19:00:58 +02:00
case SMART_POINTER :
ret < < " valueType-type= \" smart-pointer \" " ;
break ;
2017-04-16 09:11:20 +02:00
case CONTAINER :
ret < < " valueType-type= \" container \" " ;
break ;
case ITERATOR :
ret < < " valueType-type= \" iterator \" " ;
break ;
case VOID :
ret < < " valueType-type= \" void \" " ;
break ;
case BOOL :
ret < < " valueType-type= \" bool \" " ;
break ;
case CHAR :
ret < < " valueType-type= \" char \" " ;
break ;
case SHORT :
ret < < " valueType-type= \" short \" " ;
break ;
2019-05-01 16:34:28 +02:00
case WCHAR_T :
ret < < " valueType-type= \" wchar_t \" " ;
break ;
2017-04-16 09:11:20 +02:00
case INT :
ret < < " valueType-type= \" int \" " ;
break ;
case LONG :
ret < < " valueType-type= \" long \" " ;
break ;
case LONGLONG :
ret < < " valueType-type= \" long long \" " ;
break ;
case UNKNOWN_INT :
ret < < " valueType-type= \" unknown int \" " ;
break ;
case FLOAT :
ret < < " valueType-type= \" float \" " ;
break ;
case DOUBLE :
ret < < " valueType-type= \" double \" " ;
break ;
case LONGDOUBLE :
ret < < " valueType-type= \" long double \" " ;
break ;
2020-04-21 17:27:51 +02:00
}
2017-04-16 09:11:20 +02:00
switch ( sign ) {
case Sign : : UNKNOWN_SIGN :
break ;
case Sign : : SIGNED :
ret < < " valueType-sign= \" signed \" " ;
break ;
case Sign : : UNSIGNED :
ret < < " valueType-sign= \" unsigned \" " ;
break ;
2020-04-21 17:27:51 +02:00
}
2017-04-16 09:11:20 +02:00
2018-05-02 20:55:11 +02:00
if ( bits > 0 )
ret < < " valueType-bits= \" " < < bits < < ' \" ' ;
2017-04-16 09:11:20 +02:00
if ( pointer > 0 )
ret < < " valueType-pointer= \" " < < pointer < < ' \" ' ;
if ( constness > 0 )
ret < < " valueType-constness= \" " < < constness < < ' \" ' ;
2020-09-03 18:44:44 +02:00
if ( reference = = Reference : : None )
ret < < " valueType-reference= \" None \" " ;
else if ( reference = = Reference : : LValue )
ret < < " valueType-reference= \" LValue \" " ;
else if ( reference = = Reference : : RValue )
ret < < " valueType-reference= \" RValue \" " ;
2017-04-16 09:11:20 +02:00
if ( typeScope )
ret < < " valueType-typeScope= \" " < < typeScope < < ' \" ' ;
if ( ! originalTypeName . empty ( ) )
2020-09-02 07:13:15 +02:00
ret < < " valueType-originalTypeName= \" " < < ErrorLogger : : toxml ( originalTypeName ) < < ' \" ' ;
2017-04-16 09:11:20 +02:00
return ret . str ( ) ;
}
2020-01-18 17:32:59 +01:00
MathLib : : bigint ValueType : : typeSize ( const cppcheck : : Platform & platform , bool p ) const
2019-03-17 13:09:15 +01:00
{
2020-01-18 17:32:59 +01:00
if ( p & & pointer )
return platform . sizeof_pointer ;
2020-01-18 11:55:50 +01:00
2020-01-18 12:29:03 +01:00
if ( typeScope & & typeScope - > definedType & & typeScope - > definedType - > sizeOf )
2020-01-18 11:55:50 +01:00
return typeScope - > definedType - > sizeOf ;
2019-03-17 13:09:15 +01:00
switch ( type ) {
case ValueType : : Type : : BOOL :
return platform . sizeof_bool ;
case ValueType : : Type : : CHAR :
return 1 ;
case ValueType : : Type : : SHORT :
return platform . sizeof_short ;
2019-05-01 16:34:28 +02:00
case ValueType : : Type : : WCHAR_T :
return platform . sizeof_wchar_t ;
2019-03-17 13:09:15 +01:00
case ValueType : : Type : : INT :
return platform . sizeof_int ;
case ValueType : : Type : : LONG :
return platform . sizeof_long ;
case ValueType : : Type : : LONGLONG :
return platform . sizeof_long_long ;
case ValueType : : Type : : FLOAT :
return platform . sizeof_float ;
case ValueType : : Type : : DOUBLE :
return platform . sizeof_double ;
case ValueType : : Type : : LONGDOUBLE :
return platform . sizeof_long_double ;
default :
2020-01-18 11:55:50 +01:00
break ;
2020-04-21 17:27:51 +02:00
}
2019-03-17 13:09:15 +01:00
2020-01-18 11:55:50 +01:00
// Unknown invalid size
return 0 ;
2019-03-17 13:09:15 +01:00
}
2022-05-13 06:51:07 +02:00
bool ValueType : : isTypeEqual ( const ValueType * that ) const
{
auto tie = [ ] ( const ValueType * vt ) {
return std : : tie ( vt - > type , vt - > container , vt - > pointer , vt - > typeScope , vt - > smartPointer ) ;
} ;
return tie ( this ) = = tie ( that ) ;
}
2015-10-07 13:38:34 +02:00
std : : string ValueType : : str ( ) const
{
std : : string ret ;
2015-10-07 19:08:26 +02:00
if ( constness & 1 )
ret = " const " ;
2015-12-29 19:58:51 +01:00
if ( type = = VOID )
ret + = " void " ;
else if ( isIntegral ( ) ) {
2015-10-07 13:38:34 +02:00
if ( sign = = SIGNED )
2015-10-07 19:08:26 +02:00
ret + = " signed " ;
2015-10-07 13:38:34 +02:00
else if ( sign = = UNSIGNED )
2015-10-07 19:08:26 +02:00
ret + = " unsigned " ;
2015-10-07 13:38:34 +02:00
if ( type = = BOOL )
2015-10-07 19:08:26 +02:00
ret + = " bool " ;
2015-10-07 13:38:34 +02:00
else if ( type = = CHAR )
2015-10-07 19:08:26 +02:00
ret + = " char " ;
2015-10-07 13:38:34 +02:00
else if ( type = = SHORT )
2015-10-07 19:08:26 +02:00
ret + = " short " ;
2019-05-01 16:34:28 +02:00
else if ( type = = WCHAR_T )
ret + = " wchar_t " ;
2015-10-07 13:38:34 +02:00
else if ( type = = INT )
2015-10-07 19:08:26 +02:00
ret + = " int " ;
2015-10-07 13:38:34 +02:00
else if ( type = = LONG )
2015-10-07 19:08:26 +02:00
ret + = " long " ;
2015-10-07 13:38:34 +02:00
else if ( type = = LONGLONG )
2015-10-07 19:08:26 +02:00
ret + = " long long " ;
2016-05-04 15:39:56 +02:00
else if ( type = = UNKNOWN_INT )
ret + = " unknown_int " ;
2015-10-07 13:38:34 +02:00
} else if ( type = = FLOAT )
2015-10-08 19:50:10 +02:00
ret + = " float " ;
2015-10-07 13:38:34 +02:00
else if ( type = = DOUBLE )
2015-10-08 19:50:10 +02:00
ret + = " double " ;
else if ( type = = LONGDOUBLE )
ret + = " long double " ;
2017-03-05 14:53:32 +01:00
else if ( ( type = = ValueType : : Type : : NONSTD | | type = = ValueType : : Type : : RECORD ) & & typeScope ) {
2016-05-08 13:15:20 +02:00
std : : string className ( typeScope - > className ) ;
2018-09-24 06:40:20 +02:00
const Scope * scope = typeScope - > definedType ? typeScope - > definedType - > enclosingScope : typeScope - > nestedIn ;
2016-05-08 17:42:53 +02:00
while ( scope & & scope - > type ! = Scope : : eGlobal ) {
if ( scope - > type = = Scope : : eClass | | scope - > type = = Scope : : eStruct | | scope - > type = = Scope : : eNamespace )
className = scope - > className + " :: " + className ;
2020-12-21 19:47:54 +01:00
scope = ( scope - > definedType & & scope - > definedType - > enclosingScope ) ? scope - > definedType - > enclosingScope : scope - > nestedIn ;
2016-05-08 13:15:20 +02:00
}
ret + = ' ' + className ;
2017-03-05 14:53:32 +01:00
} else if ( type = = ValueType : : Type : : CONTAINER & & container ) {
2017-03-05 02:09:52 +01:00
ret + = " container( " + container - > startPattern + ' ) ' ;
2017-03-05 14:53:32 +01:00
} else if ( type = = ValueType : : Type : : ITERATOR & & container ) {
ret + = " iterator( " + container - > startPattern + ' ) ' ;
2021-08-14 19:00:58 +02:00
} else if ( type = = ValueType : : Type : : SMART_POINTER & & smartPointer ) {
ret + = " smart-pointer( " + smartPointer - > name + " ) " ;
2016-05-08 13:15:20 +02:00
}
2016-05-06 15:22:45 +02:00
for ( unsigned int p = 0 ; p < pointer ; p + + ) {
2015-10-07 19:08:26 +02:00
ret + = " * " ;
if ( constness & ( 2 < < p ) )
2015-10-07 19:50:50 +02:00
ret + = " const " ;
}
2020-09-03 18:44:44 +02:00
if ( reference = = Reference : : LValue )
ret + = " & " ;
else if ( reference = = Reference : : RValue )
ret + = " && " ;
2016-01-01 15:13:50 +01:00
return ret . empty ( ) ? ret : ret . substr ( 1 ) ;
2015-10-07 13:38:34 +02:00
}
2019-07-29 18:14:06 +02:00
2022-06-15 21:25:55 +02:00
void ValueType : : setDebugPath ( const Token * tok , SourceLocation ctx , SourceLocation local )
{
std : : string file = ctx . file_name ( ) ;
if ( file . empty ( ) )
return ;
std : : string s = Path : : stripDirectoryPart ( file ) + " : " + MathLib : : toString ( ctx . line ( ) ) + " : " + ctx . function_name ( ) +
" => " + local . function_name ( ) ;
2022-09-10 11:25:15 +02:00
debugPath . emplace_back ( tok , std : : move ( s ) ) ;
2022-06-15 21:25:55 +02:00
}
2019-07-29 18:14:06 +02:00
ValueType : : MatchResult ValueType : : matchParameter ( const ValueType * call , const ValueType * func )
{
if ( ! call | | ! func )
return ValueType : : MatchResult : : UNKNOWN ;
2019-07-31 12:38:36 +02:00
if ( call - > pointer ! = func - > pointer ) {
2019-07-31 16:23:50 +02:00
if ( call - > pointer > 1 & & func - > pointer = = 1 & & func - > type = = ValueType : : Type : : VOID )
return ValueType : : MatchResult : : FALLBACK1 ;
2019-10-30 21:05:42 +01:00
if ( call - > pointer = = 1 & & func - > pointer = = 0 & & func - > isIntegral ( ) & & func - > sign ! = ValueType : : Sign : : SIGNED )
return ValueType : : MatchResult : : FALLBACK1 ;
2019-08-03 10:10:22 +02:00
if ( call - > pointer = = 1 & & call - > type = = ValueType : : Type : : CHAR & & func - > pointer = = 0 & & func - > container & & func - > container - > stdStringLike )
return ValueType : : MatchResult : : FALLBACK2 ;
2019-07-31 18:55:55 +02:00
return ValueType : : MatchResult : : NOMATCH ; // TODO
2019-07-31 12:38:36 +02:00
}
2022-02-02 19:38:32 +01:00
if ( call - > pointer > 0 ) {
if ( ( call - > constness | func - > constness ) ! = func - > constness )
return ValueType : : MatchResult : : NOMATCH ;
if ( call - > constness = = 0 & & func - > constness ! = 0 & & func - > reference ! = Reference : : None )
return ValueType : : MatchResult : : NOMATCH ;
}
2019-07-29 21:53:39 +02:00
if ( call - > type ! = func - > type ) {
2019-07-31 12:12:17 +02:00
if ( call - > type = = ValueType : : Type : : VOID | | func - > type = = ValueType : : Type : : VOID )
2019-07-30 21:02:12 +02:00
return ValueType : : MatchResult : : FALLBACK1 ;
2022-02-02 19:38:32 +01:00
if ( call - > pointer > 0 )
2019-09-11 19:25:09 +02:00
return func - > type = = ValueType : : UNKNOWN_TYPE ? ValueType : : MatchResult : : UNKNOWN : ValueType : : MatchResult : : NOMATCH ;
2019-07-29 21:53:39 +02:00
if ( call - > isIntegral ( ) & & func - > isIntegral ( ) )
2019-07-30 07:48:14 +02:00
return call - > type < func - > type ?
ValueType : : MatchResult : : FALLBACK1 :
ValueType : : MatchResult : : FALLBACK2 ;
2019-07-29 21:53:39 +02:00
else if ( call - > isFloat ( ) & & func - > isFloat ( ) )
return ValueType : : MatchResult : : FALLBACK1 ;
else if ( call - > isIntegral ( ) & & func - > isFloat ( ) )
return ValueType : : MatchResult : : FALLBACK2 ;
else if ( call - > isFloat ( ) & & func - > isIntegral ( ) )
return ValueType : : MatchResult : : FALLBACK2 ;
2019-07-29 18:14:06 +02:00
return ValueType : : MatchResult : : UNKNOWN ; // TODO
2019-07-29 21:53:39 +02:00
}
2021-04-08 16:02:11 +02:00
if ( call - > typeScope ! = nullptr | | func - > typeScope ! = nullptr ) {
if ( call - > typeScope ! = func - > typeScope )
return ValueType : : MatchResult : : NOMATCH ;
}
2019-07-31 18:35:56 +02:00
2019-08-03 10:10:22 +02:00
if ( call - > container ! = nullptr | | func - > container ! = nullptr ) {
if ( call - > container ! = func - > container )
return ValueType : : MatchResult : : NOMATCH ;
}
2019-08-02 15:59:22 +02:00
2021-04-08 16:02:11 +02:00
if ( func - > typeScope ! = nullptr & & func - > container ! = nullptr ) {
if ( func - > type < ValueType : : Type : : VOID | | func - > type = = ValueType : : Type : : UNKNOWN_INT )
return ValueType : : MatchResult : : UNKNOWN ;
}
2019-07-29 18:14:06 +02:00
2019-07-30 21:02:12 +02:00
if ( call - > isIntegral ( ) & & func - > isIntegral ( ) & & call - > sign ! = ValueType : : Sign : : UNKNOWN_SIGN & & func - > sign ! = ValueType : : Sign : : UNKNOWN_SIGN & & call - > sign ! = func - > sign )
2019-10-06 12:05:58 +02:00
return ValueType : : MatchResult : : FALLBACK1 ;
2019-07-29 21:53:39 +02:00
2021-04-08 16:02:11 +02:00
if ( func - > reference ! = Reference : : None & & func - > constness > call - > constness )
return ValueType : : MatchResult : : FALLBACK1 ;
2019-07-29 18:14:06 +02:00
return ValueType : : MatchResult : : SAME ;
}
2019-08-03 10:10:22 +02:00
ValueType : : MatchResult ValueType : : matchParameter ( const ValueType * call , const Variable * callVar , const Variable * funcVar )
{
2022-01-12 22:05:30 +01:00
ValueType vt ;
const ValueType * pvt = funcVar - > valueType ( ) ;
2022-01-14 17:55:50 +01:00
if ( pvt & & funcVar - > isArray ( ) & & ! ( funcVar - > isStlType ( ) & & Token : : simpleMatch ( funcVar - > typeStartToken ( ) , " std :: array " ) ) ) { // std::array doesn't decay to a pointer
2022-01-12 22:05:30 +01:00
vt = * pvt ;
2022-01-14 17:55:50 +01:00
if ( vt . pointer = = 0 ) // don't bump array of pointers
+ + vt . pointer ;
2022-01-12 22:05:30 +01:00
pvt = & vt ;
}
2022-10-02 07:12:40 +02:00
const ValueType : : MatchResult res = ValueType : : matchParameter ( call , pvt ) ;
2021-04-09 07:44:20 +02:00
if ( callVar & & ( ( res = = ValueType : : MatchResult : : SAME & & call - > container ) | | res = = ValueType : : MatchResult : : UNKNOWN ) ) {
2019-08-03 10:10:22 +02:00
const std : : string type1 = getTypeString ( callVar - > typeStartToken ( ) ) ;
const std : : string type2 = getTypeString ( funcVar - > typeStartToken ( ) ) ;
2021-06-04 17:15:39 +02:00
const bool templateVar =
funcVar - > scope ( ) & & funcVar - > scope ( ) - > function & & funcVar - > scope ( ) - > function - > templateDef ;
if ( type1 = = type2 )
return ValueType : : MatchResult : : SAME ;
2021-08-26 07:46:40 +02:00
if ( ! templateVar & & type1 . find ( " auto " ) = = std : : string : : npos & & type2 . find ( " auto " ) = = std : : string : : npos )
2019-08-03 10:10:22 +02:00
return ValueType : : MatchResult : : NOMATCH ;
}
return res ;
}