2012-05-05 18:33:26 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2023-01-28 10:16:34 +01:00
* Copyright ( C ) 2007 - 2023 Cppcheck team .
2012-05-05 18:33:26 +02: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 "tokenlist.h"
2017-05-27 04:33:47 +02:00
2021-07-09 07:22:24 +02:00
# include "astutils.h"
2017-05-27 04:33:47 +02:00
# include "errorlogger.h"
2022-01-27 19:03:20 +01:00
# include "errortypes.h"
2023-02-24 21:43:27 +01:00
# include "keywords.h"
2020-04-13 13:44:48 +02:00
# include "library.h"
2022-08-14 12:44:19 +02:00
# include "mathlib.h"
2012-05-05 18:33:26 +02:00
# include "path.h"
2023-04-08 16:08:47 +02:00
# include "platform.h"
2012-05-05 18:33:26 +02:00
# include "settings.h"
2020-04-13 13:44:48 +02:00
# include "standards.h"
2017-05-27 04:33:47 +02:00
# include "token.h"
2017-05-18 22:25:49 +02:00
2022-01-27 19:03:20 +01:00
# include <algorithm>
2012-05-05 18:33:26 +02:00
# include <cctype>
2022-01-27 19:03:20 +01:00
# include <exception>
# include <functional>
# include <utility>
2017-05-27 04:33:47 +02:00
# include <set>
2012-05-05 18:33:26 +02:00
# include <stack>
2023-03-04 08:53:19 +01:00
# include <unordered_set>
2012-05-05 18:33:26 +02:00
2022-01-27 19:03:20 +01:00
# include <simplecpp.h>
2014-04-15 06:31:09 +02:00
// How many compileExpression recursions are allowed?
// For practical code this could be endless. But in some special torture test
// there needs to be a limit.
2023-01-26 20:12:39 +01:00
static const int AST_MAX_DEPTH = 150 ;
2014-04-15 06:31:09 +02:00
2012-05-05 18:33:26 +02:00
TokenList : : TokenList ( const Settings * settings ) :
2023-08-08 11:05:02 +02:00
mSettings ( settings )
2012-05-05 18:33:26 +02:00
{
2020-05-17 17:25:33 +02:00
mTokensFrontBack . list = this ;
2012-05-05 18:33:26 +02:00
}
TokenList : : ~ TokenList ( )
{
deallocateTokens ( ) ;
}
//---------------------------------------------------------------------------
2014-06-04 18:00:22 +02:00
const std : : string & TokenList : : getSourceFilePath ( ) const
{
if ( getFiles ( ) . empty ( ) ) {
2014-06-26 11:44:19 +02:00
return emptyString ;
2014-06-04 18:00:22 +02:00
}
return getFiles ( ) [ 0 ] ;
}
//---------------------------------------------------------------------------
2012-05-05 18:33:26 +02:00
// Deallocate lists..
void TokenList : : deallocateTokens ( )
{
2018-06-16 16:22:35 +02:00
deleteTokens ( mTokensFrontBack . front ) ;
mTokensFrontBack . front = nullptr ;
mTokensFrontBack . back = nullptr ;
2018-06-16 16:23:55 +02:00
mFiles . clear ( ) ;
2012-05-05 18:33:26 +02:00
}
2020-05-17 17:25:33 +02:00
void TokenList : : determineCppC ( )
{
if ( ! mSettings ) {
mIsC = Path : : isC ( getSourceFilePath ( ) ) ;
mIsCpp = Path : : isCPP ( getSourceFilePath ( ) ) ;
} else {
2022-11-20 12:29:56 +01:00
mIsC = mSettings - > enforcedLang = = Settings : : Language : : C | | ( mSettings - > enforcedLang = = Settings : : Language : : None & & Path : : isC ( getSourceFilePath ( ) ) ) ;
mIsCpp = mSettings - > enforcedLang = = Settings : : Language : : CPP | | ( mSettings - > enforcedLang = = Settings : : Language : : None & & Path : : isCPP ( getSourceFilePath ( ) ) ) ;
2020-05-17 17:25:33 +02:00
}
}
2022-09-08 09:21:35 +02:00
int TokenList : : appendFileIfNew ( std : : string fileName )
2014-01-28 17:15:07 +01:00
{
// Has this file been tokenized already?
2019-07-17 10:14:00 +02:00
for ( int i = 0 ; i < mFiles . size ( ) ; + + i )
2018-06-16 16:23:55 +02:00
if ( Path : : sameFileName ( mFiles [ i ] , fileName ) )
2019-07-17 10:14:00 +02:00
return i ;
2014-01-28 17:15:07 +01:00
2018-06-16 16:23:55 +02:00
// The "mFiles" vector remembers what files have been tokenized..
2022-09-08 09:21:35 +02:00
mFiles . push_back ( std : : move ( fileName ) ) ;
2014-06-24 17:34:20 +02:00
2018-06-16 16:28:03 +02:00
// Update mIsC and mIsCpp properties
2018-06-16 16:23:55 +02:00
if ( mFiles . size ( ) = = 1 ) { // Update only useful if first file added to _files
2020-05-17 17:25:33 +02:00
determineCppC ( ) ;
2014-06-24 17:34:20 +02:00
}
2019-07-17 10:14:00 +02:00
return mFiles . size ( ) - 1 ;
2014-01-28 17:15:07 +01:00
}
2021-04-30 16:47:02 +02:00
void TokenList : : clangSetOrigFiles ( )
{
mOrigFiles = mFiles ;
}
2012-05-05 18:33:26 +02:00
void TokenList : : deleteTokens ( Token * tok )
{
while ( tok ) {
Token * next = tok - > next ( ) ;
delete tok ;
tok = next ;
}
}
//---------------------------------------------------------------------------
// add a token.
//---------------------------------------------------------------------------
2022-05-08 20:42:06 +02:00
void TokenList : : addtoken ( const std : : string & str , const nonneg int lineno , const nonneg int column , const nonneg int fileno , bool split )
2012-05-05 18:33:26 +02:00
{
2014-03-09 17:54:49 +01:00
if ( str . empty ( ) )
2012-05-05 18:33:26 +02:00
return ;
// If token contains # characters, split it up
2014-03-09 17:54:49 +01:00
if ( split ) {
size_t begin = 0 ;
size_t end = 0 ;
while ( ( end = str . find ( " ## " , begin ) ) ! = std : : string : : npos ) {
addtoken ( str . substr ( begin , end - begin ) , lineno , fileno , false ) ;
2020-12-08 10:34:23 +01:00
addtoken ( " ## " , lineno , column , fileno , false ) ;
2014-03-09 17:54:49 +01:00
begin = end + 2 ;
}
if ( begin ! = 0 ) {
2020-12-08 10:34:23 +01:00
addtoken ( str . substr ( begin ) , lineno , column , fileno , false ) ;
2014-03-09 17:54:49 +01:00
return ;
2012-05-05 18:33:26 +02:00
}
}
2018-06-16 16:22:35 +02:00
if ( mTokensFrontBack . back ) {
mTokensFrontBack . back - > insertToken ( str ) ;
2012-05-05 18:33:26 +02:00
} else {
2018-06-16 16:22:35 +02:00
mTokensFrontBack . front = new Token ( & mTokensFrontBack ) ;
mTokensFrontBack . back = mTokensFrontBack . front ;
mTokensFrontBack . back - > str ( str ) ;
2012-05-05 18:33:26 +02:00
}
2018-06-16 16:22:35 +02:00
mTokensFrontBack . back - > linenr ( lineno ) ;
2020-12-08 10:34:23 +01:00
mTokensFrontBack . back - > column ( column ) ;
2018-06-16 16:22:35 +02:00
mTokensFrontBack . back - > fileIndex ( fileno ) ;
2012-05-05 18:33:26 +02:00
}
2022-05-08 20:42:06 +02:00
void TokenList : : addtoken ( const std : : string & str , const Token * locationTok )
2019-08-17 07:38:07 +02:00
{
if ( str . empty ( ) )
return ;
if ( mTokensFrontBack . back ) {
mTokensFrontBack . back - > insertToken ( str ) ;
} else {
mTokensFrontBack . front = new Token ( & mTokensFrontBack ) ;
mTokensFrontBack . back = mTokensFrontBack . front ;
mTokensFrontBack . back - > str ( str ) ;
}
mTokensFrontBack . back - > linenr ( locationTok - > linenr ( ) ) ;
2019-08-18 12:19:05 +02:00
mTokensFrontBack . back - > column ( locationTok - > column ( ) ) ;
2019-08-17 07:38:07 +02:00
mTokensFrontBack . back - > fileIndex ( locationTok - > fileIndex ( ) ) ;
}
2020-12-08 10:34:23 +01:00
void TokenList : : addtoken ( const Token * tok , const nonneg int lineno , const nonneg int column , const nonneg int fileno )
2012-05-05 18:33:26 +02:00
{
2015-05-27 21:39:31 +02:00
if ( tok = = nullptr )
2012-05-05 18:33:26 +02:00
return ;
2018-06-16 16:22:35 +02:00
if ( mTokensFrontBack . back ) {
mTokensFrontBack . back - > insertToken ( tok - > str ( ) , tok - > originalName ( ) ) ;
2012-05-05 18:33:26 +02:00
} else {
2018-06-16 16:22:35 +02:00
mTokensFrontBack . front = new Token ( & mTokensFrontBack ) ;
mTokensFrontBack . back = mTokensFrontBack . front ;
mTokensFrontBack . back - > str ( tok - > str ( ) ) ;
2014-06-26 10:57:39 +02:00
if ( ! tok - > originalName ( ) . empty ( ) )
2018-06-16 16:22:35 +02:00
mTokensFrontBack . back - > originalName ( tok - > originalName ( ) ) ;
2012-05-05 18:33:26 +02:00
}
2018-06-16 16:22:35 +02:00
mTokensFrontBack . back - > linenr ( lineno ) ;
2020-12-08 10:34:23 +01:00
mTokensFrontBack . back - > column ( column ) ;
2018-06-16 16:22:35 +02:00
mTokensFrontBack . back - > fileIndex ( fileno ) ;
mTokensFrontBack . back - > flags ( tok - > flags ( ) ) ;
2012-05-05 18:33:26 +02:00
}
2018-01-07 14:07:34 +01:00
2019-08-17 07:38:07 +02:00
void TokenList : : addtoken ( const Token * tok , const Token * locationTok )
{
if ( tok = = nullptr | | locationTok = = nullptr )
return ;
if ( mTokensFrontBack . back ) {
mTokensFrontBack . back - > insertToken ( tok - > str ( ) , tok - > originalName ( ) ) ;
} else {
mTokensFrontBack . front = new Token ( & mTokensFrontBack ) ;
mTokensFrontBack . back = mTokensFrontBack . front ;
mTokensFrontBack . back - > str ( tok - > str ( ) ) ;
if ( ! tok - > originalName ( ) . empty ( ) )
mTokensFrontBack . back - > originalName ( tok - > originalName ( ) ) ;
}
mTokensFrontBack . back - > flags ( tok - > flags ( ) ) ;
mTokensFrontBack . back - > linenr ( locationTok - > linenr ( ) ) ;
2019-08-18 12:19:05 +02:00
mTokensFrontBack . back - > column ( locationTok - > column ( ) ) ;
2019-08-17 07:38:07 +02:00
mTokensFrontBack . back - > fileIndex ( locationTok - > fileIndex ( ) ) ;
}
void TokenList : : addtoken ( const Token * tok )
{
if ( tok = = nullptr )
return ;
if ( mTokensFrontBack . back ) {
mTokensFrontBack . back - > insertToken ( tok - > str ( ) , tok - > originalName ( ) ) ;
} else {
mTokensFrontBack . front = new Token ( & mTokensFrontBack ) ;
mTokensFrontBack . back = mTokensFrontBack . front ;
mTokensFrontBack . back - > str ( tok - > str ( ) ) ;
if ( ! tok - > originalName ( ) . empty ( ) )
mTokensFrontBack . back - > originalName ( tok - > originalName ( ) ) ;
}
mTokensFrontBack . back - > flags ( tok - > flags ( ) ) ;
mTokensFrontBack . back - > linenr ( tok - > linenr ( ) ) ;
2019-08-18 12:19:05 +02:00
mTokensFrontBack . back - > column ( tok - > column ( ) ) ;
2019-08-17 07:38:07 +02:00
mTokensFrontBack . back - > fileIndex ( tok - > fileIndex ( ) ) ;
}
2018-01-07 14:07:34 +01:00
//---------------------------------------------------------------------------
// copyTokens - Copy and insert tokens
//---------------------------------------------------------------------------
Token * TokenList : : copyTokens ( Token * dest , const Token * first , const Token * last , bool one_line )
{
std : : stack < Token * > links ;
Token * tok2 = dest ;
2019-07-17 10:14:00 +02:00
int linenr = dest - > linenr ( ) ;
const int commonFileIndex = dest - > fileIndex ( ) ;
2018-01-07 14:07:34 +01:00
for ( const Token * tok = first ; tok ! = last - > next ( ) ; tok = tok - > next ( ) ) {
tok2 - > insertToken ( tok - > str ( ) ) ;
tok2 = tok2 - > next ( ) ;
tok2 - > fileIndex ( commonFileIndex ) ;
2019-07-17 10:14:00 +02:00
tok2 - > linenr ( linenr ) ;
2018-01-07 14:07:34 +01:00
tok2 - > tokType ( tok - > tokType ( ) ) ;
tok2 - > flags ( tok - > flags ( ) ) ;
tok2 - > varId ( tok - > varId ( ) ) ;
2022-06-01 06:53:21 +02:00
tok2 - > setTokenDebug ( tok - > getTokenDebug ( ) ) ;
2018-01-07 14:07:34 +01:00
// Check for links and fix them up
if ( Token : : Match ( tok2 , " (|[|{ " ) )
links . push ( tok2 ) ;
else if ( Token : : Match ( tok2 , " ) | ] | } " )) {
if ( links . empty ( ) )
return tok2 ;
Token * link = links . top ( ) ;
tok2 - > link ( link ) ;
link - > link ( tok2 ) ;
links . pop ( ) ;
}
if ( ! one_line & & tok - > next ( ) )
2019-07-17 10:14:00 +02:00
linenr + = tok - > next ( ) - > linenr ( ) - tok - > linenr ( ) ;
2018-01-07 14:07:34 +01:00
}
return tok2 ;
}
2012-05-05 18:33:26 +02:00
//---------------------------------------------------------------------------
// InsertTokens - Copy and insert tokens
//---------------------------------------------------------------------------
2019-07-17 10:14:00 +02:00
void TokenList : : insertTokens ( Token * dest , const Token * src , nonneg int n )
2012-05-05 18:33:26 +02:00
{
std : : stack < Token * > link ;
while ( n > 0 ) {
2013-09-24 06:43:03 +02:00
dest - > insertToken ( src - > str ( ) , src - > originalName ( ) ) ;
2012-05-05 18:33:26 +02:00
dest = dest - > next ( ) ;
// Set links
if ( Token : : Match ( dest , " (|[|{ " ) )
link . push ( dest ) ;
else if ( ! link . empty ( ) & & Token : : Match ( dest , " )|]|} " ) ) {
Token : : createMutualLinks ( dest , link . top ( ) ) ;
link . pop ( ) ;
}
dest - > fileIndex ( src - > fileIndex ( ) ) ;
dest - > linenr ( src - > linenr ( ) ) ;
2019-08-20 20:53:17 +02:00
dest - > column ( src - > column ( ) ) ;
2012-05-05 18:33:26 +02:00
dest - > varId ( src - > varId ( ) ) ;
2015-08-14 20:46:13 +02:00
dest - > tokType ( src - > tokType ( ) ) ;
2014-05-06 06:35:48 +02:00
dest - > flags ( src - > flags ( ) ) ;
2012-05-05 18:33:26 +02:00
src = src - > next ( ) ;
- - n ;
}
}
//---------------------------------------------------------------------------
// Tokenize - tokenizes a given file.
//---------------------------------------------------------------------------
bool TokenList : : createTokens ( std : : istream & code , const std : : string & file0 )
{
2014-06-24 17:34:20 +02:00
appendFileIfNew ( file0 ) ;
2012-05-05 18:33:26 +02:00
2017-05-18 21:52:31 +02:00
simplecpp : : OutputList outputList ;
2018-06-16 16:23:55 +02:00
simplecpp : : TokenList tokens ( code , mFiles , file0 , & outputList ) ;
2015-12-27 14:57:22 +01:00
2020-05-16 18:44:17 +02:00
createTokens ( std : : move ( tokens ) ) ;
2012-05-05 18:33:26 +02:00
2017-05-18 21:52:31 +02:00
return outputList . empty ( ) ;
2012-05-05 18:33:26 +02:00
}
2014-09-02 18:05:02 +02:00
//---------------------------------------------------------------------------
2020-05-16 18:44:17 +02:00
void TokenList : : createTokens ( simplecpp : : TokenList & & tokenList )
2017-05-17 14:57:54 +02:00
{
2020-05-16 18:44:17 +02:00
if ( tokenList . cfront ( ) )
mOrigFiles = mFiles = tokenList . cfront ( ) - > location . files ;
2017-05-17 14:57:54 +02:00
else
2018-06-16 16:23:55 +02:00
mFiles . clear ( ) ;
2017-05-17 14:57:54 +02:00
2020-05-17 17:25:33 +02:00
determineCppC ( ) ;
2017-05-17 14:57:54 +02:00
2020-05-16 18:44:17 +02:00
for ( const simplecpp : : Token * tok = tokenList . cfront ( ) ; tok ; ) {
2017-05-18 21:52:31 +02:00
2018-05-14 13:00:22 +02:00
std : : string str = tok - > str ( ) ;
2017-05-18 21:52:31 +02:00
// Float literal
if ( str . size ( ) > 1 & & str [ 0 ] = = ' . ' & & std : : isdigit ( str [ 1 ] ) )
str = ' 0 ' + str ;
2018-06-16 16:22:35 +02:00
if ( mTokensFrontBack . back ) {
mTokensFrontBack . back - > insertToken ( str ) ;
2017-05-17 14:57:54 +02:00
} else {
2018-06-16 16:22:35 +02:00
mTokensFrontBack . front = new Token ( & mTokensFrontBack ) ;
mTokensFrontBack . back = mTokensFrontBack . front ;
mTokensFrontBack . back - > str ( str ) ;
2017-05-17 14:57:54 +02:00
}
2018-06-16 16:22:35 +02:00
mTokensFrontBack . back - > fileIndex ( tok - > location . fileIndex ) ;
mTokensFrontBack . back - > linenr ( tok - > location . line ) ;
2019-08-18 12:19:05 +02:00
mTokensFrontBack . back - > column ( tok - > location . col ) ;
2018-06-16 16:22:35 +02:00
mTokensFrontBack . back - > isExpandedMacro ( ! tok - > macro . empty ( ) ) ;
2020-05-16 18:44:17 +02:00
tok = tok - > next ;
if ( tok )
tokenList . deleteToken ( tok - > previous ) ;
2017-05-17 14:57:54 +02:00
}
2018-06-16 16:10:28 +02:00
if ( mSettings & & mSettings - > relativePaths ) {
2019-09-19 20:29:33 +02:00
for ( std : : string & mFile : mFiles )
mFile = Path : : getRelativePath ( mFile , mSettings - > basePaths ) ;
2017-05-17 14:57:54 +02:00
}
2018-06-16 16:22:35 +02:00
Token : : assignProgressValues ( mTokensFrontBack . front ) ;
2017-05-17 14:57:54 +02:00
}
//---------------------------------------------------------------------------
2022-07-07 12:16:01 +02:00
std : : size_t TokenList : : calculateHash ( ) const
2014-09-02 18:05:02 +02:00
{
2022-07-07 12:16:01 +02:00
std : : string hashData ;
2014-09-02 18:05:02 +02:00
for ( const Token * tok = front ( ) ; tok ; tok = tok - > next ( ) ) {
2022-07-07 12:16:01 +02:00
hashData + = MathLib : : toString ( tok - > flags ( ) ) ;
hashData + = MathLib : : toString ( tok - > varId ( ) ) ;
hashData + = MathLib : : toString ( tok - > tokType ( ) ) ;
hashData + = tok - > str ( ) ;
hashData + = tok - > originalName ( ) ;
2014-09-02 18:05:02 +02:00
}
2022-07-07 12:16:01 +02:00
return ( std : : hash < std : : string > { } ) ( hashData ) ;
2014-09-02 18:05:02 +02:00
}
2012-05-05 18:33:26 +02:00
//---------------------------------------------------------------------------
2014-06-04 22:33:08 +02:00
struct AST_state {
std : : stack < Token * > op ;
2023-08-08 11:05:02 +02:00
int depth { } ;
int inArrayAssignment { } ;
2014-06-04 22:33:08 +02:00
bool cpp ;
2023-08-08 11:05:02 +02:00
int assign { } ;
bool inCase { } ; // true from case to :
bool stopAtColon { } ; // help to properly parse ternary operators
const Token * functionCallEndPar { } ;
explicit AST_state ( bool cpp ) : cpp ( cpp ) { }
2014-06-04 22:33:08 +02:00
} ;
2022-02-22 06:30:17 +01:00
static Token * skipDecl ( Token * tok , std : : vector < Token * > * inner = nullptr )
2016-01-26 10:40:44 +01:00
{
2022-11-01 11:50:08 +01:00
auto isDecltypeFuncParam = [ ] ( const Token * tok ) - > bool {
if ( ! Token : : simpleMatch ( tok , " ) " ) )
return false ;
tok = tok - > next ( ) ;
while ( Token : : Match ( tok , " *|&|&&|const " ) )
tok = tok - > next ( ) ;
if ( Token : : simpleMatch ( tok , " ( " ) )
tok = tok - > link ( ) - > next ( ) ;
return Token : : Match ( tok , " %name%| ,|) " ) ;
} ;
2016-01-26 10:40:44 +01:00
if ( ! Token : : Match ( tok - > previous ( ) , " ( %name% " ) )
return tok ;
Token * vartok = tok ;
while ( Token : : Match ( vartok , " %name%|*|&|::|< " ) ) {
if ( vartok - > str ( ) = = " < " ) {
if ( vartok - > link ( ) )
vartok = vartok - > link ( ) ;
else
return tok ;
2020-04-19 17:00:08 +02:00
} else if ( Token : : Match ( vartok , " %var% [:=(] " ) ) {
2016-01-26 10:40:44 +01:00
return vartok ;
2022-11-01 11:50:08 +01:00
} else if ( Token : : Match ( vartok , " decltype|typeof ( " ) & & ! isDecltypeFuncParam ( tok - > linkAt ( 1 ) ) ) {
2022-02-22 06:30:17 +01:00
if ( inner )
inner - > push_back ( vartok - > tokAt ( 2 ) ) ;
2020-08-16 21:11:18 +02:00
return vartok - > linkAt ( 1 ) - > next ( ) ;
}
2016-01-26 10:40:44 +01:00
vartok = vartok - > next ( ) ;
}
return tok ;
}
2020-11-15 10:37:29 +01:00
static bool iscast ( const Token * tok , bool cpp )
2013-11-11 16:39:34 +01:00
{
2016-01-25 10:29:24 +01:00
if ( ! Token : : Match ( tok , " ( ::| %name% " ) )
2013-11-11 16:39:34 +01:00
return false ;
2018-09-04 18:10:31 +02:00
if ( Token : : simpleMatch ( tok - > link ( ) , " ) ( ) " ) )
return false ;
2020-11-15 10:37:29 +01:00
if ( tok - > previous ( ) & & tok - > previous ( ) - > isName ( ) & & tok - > previous ( ) - > str ( ) ! = " return " & &
2022-03-22 18:39:02 +01:00
( ! cpp | | ! Token : : Match ( tok - > previous ( ) , " delete|throw " ) ) )
2014-05-17 12:09:32 +02:00
return false ;
2018-06-02 15:57:56 +02:00
if ( Token : : simpleMatch ( tok - > previous ( ) , " > " ) & & tok - > previous ( ) - > link ( ) )
2016-01-03 09:38:03 +01:00
return false ;
2016-01-03 09:37:38 +01:00
2014-05-04 18:36:04 +02:00
if ( Token : : Match ( tok , " ( (| typeof ( " ) & & Token : : Match ( tok - > link ( ) , " ) %num% " ) )
return true ;
2019-05-11 15:50:30 +02:00
if ( Token : : Match ( tok - > link ( ) , " ) }|)|]|; " ) )
2018-03-27 13:44:28 +02:00
return false ;
2020-02-21 17:15:33 +01:00
if ( Token : : Match ( tok - > link ( ) , " ) %cop% " ) & & ! Token : : Match ( tok - > link ( ) , " ) [&*+-~!] " ) )
2018-03-27 13:44:28 +02:00
return false ;
2018-06-02 15:57:56 +02:00
if ( Token : : Match ( tok - > previous ( ) , " = ( %name% ) { " ) & & tok - > next ( ) - > varId ( ) = = 0 )
2017-04-21 17:44:11 +02:00
return true ;
2014-05-24 19:04:47 +02:00
bool type = false ;
2013-11-11 16:39:34 +01:00
for ( const Token * tok2 = tok - > next ( ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
2018-11-14 21:05:03 +01:00
if ( tok2 - > varId ( ) ! = 0 )
return false ;
2022-09-27 18:12:58 +02:00
if ( cpp & & ! type & & tok2 - > str ( ) = = " new " )
return false ;
2018-11-14 21:05:03 +01:00
2014-05-24 20:21:08 +02:00
while ( tok2 - > link ( ) & & Token : : Match ( tok2 , " (|[|< " ) )
2014-05-24 11:28:43 +02:00
tok2 = tok2 - > link ( ) - > next ( ) ;
2017-09-08 22:52:16 +02:00
if ( tok2 - > str ( ) = = " ) " ) {
2018-11-14 21:05:03 +01:00
if ( Token : : simpleMatch ( tok2 , " ) ( " ) & & Token : : simpleMatch ( tok2 - > linkAt ( 1 ) , " ) . " ) )
return true ;
2020-03-08 16:21:22 +01:00
if ( Token : : simpleMatch ( tok2 , " ) { " ) & & ! type ) {
const Token * tok3 = tok2 - > linkAt ( 1 ) ;
while ( tok3 ! = tok2 & & Token : : Match ( tok3 , " [{}] " ) )
tok3 = tok3 - > previous ( ) ;
2023-03-09 20:01:06 +01:00
return tok3 - > str ( ) ! = " ; " ;
2020-03-08 16:21:22 +01:00
}
2023-03-09 20:01:06 +01:00
const bool res = type | | tok2 - > strAt ( - 1 ) = = " * " | | Token : : simpleMatch ( tok2 , " ) ~ " ) | |
( Token : : Match ( tok2 , " ) %any% " ) & &
( ! tok2 - > next ( ) - > isOp ( ) | | Token : : Match ( tok2 - > next ( ) , " !|~|++|-- " ) ) & &
! Token : : Match ( tok2 - > next ( ) , " [[]);,?:.] " ) ) ;
return res ;
2017-09-08 22:52:16 +02:00
}
2020-02-25 21:05:36 +01:00
if ( Token : : Match ( tok2 , " &|&& ) " ) )
return true ;
if ( ! Token : : Match ( tok2 , " %name%|*|:: " ) )
2014-04-15 15:46:26 +02:00
return false ;
2014-05-24 11:28:43 +02:00
2017-04-10 23:44:30 +02:00
if ( tok2 - > isStandardType ( ) & & ( tok2 - > next ( ) - > str ( ) ! = " ( " | | Token : : Match ( tok2 - > next ( ) , " ( * *| ) " ) ) )
2014-05-24 19:04:47 +02:00
type = true ;
2013-11-11 16:39:34 +01:00
}
return false ;
}
2017-05-24 20:18:31 +02:00
// int(1), int*(2), ..
static Token * findCppTypeInitPar ( Token * tok )
{
2017-05-24 20:24:56 +02:00
if ( ! tok | | ! Token : : Match ( tok - > previous ( ) , " [,()] %name% " ) )
2017-05-24 20:18:31 +02:00
return nullptr ;
2017-08-26 23:25:45 +02:00
bool istype = false ;
2017-05-24 20:18:31 +02:00
while ( Token : : Match ( tok , " %name%|::|< " ) ) {
if ( tok - > str ( ) = = " < " ) {
tok = tok - > link ( ) ;
if ( ! tok )
return nullptr ;
}
2017-08-26 23:25:45 +02:00
istype | = tok - > isStandardType ( ) ;
2017-05-24 20:18:31 +02:00
tok = tok - > next ( ) ;
}
2017-08-26 23:25:45 +02:00
if ( ! istype )
return nullptr ;
2017-05-24 20:18:31 +02:00
if ( ! Token : : Match ( tok , " [*&] " ) )
return nullptr ;
while ( Token : : Match ( tok , " [*&] " ) )
tok = tok - > next ( ) ;
return ( tok & & tok - > str ( ) = = " ( " ) ? tok : nullptr ;
}
2015-10-18 13:43:39 +02:00
// X{} X<Y>{} etc
2019-09-02 20:31:01 +02:00
static bool iscpp11init_impl ( const Token * const tok ) ;
2015-10-18 16:58:15 +02:00
static bool iscpp11init ( const Token * const tok )
2019-09-02 20:31:01 +02:00
{
if ( tok - > isCpp11init ( ) = = TokenImpl : : Cpp11init : : UNKNOWN )
tok - > setCpp11init ( iscpp11init_impl ( tok ) ) ;
return tok - > isCpp11init ( ) = = TokenImpl : : Cpp11init : : CPP11INIT ;
}
static bool iscpp11init_impl ( const Token * const tok )
2015-10-18 13:43:39 +02:00
{
2019-11-19 11:38:03 +01:00
if ( Token : : simpleMatch ( tok , " { " ) & & Token : : simpleMatch ( tok - > link ( ) - > previous ( ) , " ; } " ) )
return false ;
2017-06-09 22:35:46 +02:00
const Token * nameToken = tok ;
while ( nameToken & & nameToken - > str ( ) = = " { " ) {
2019-09-03 06:43:08 +02:00
if ( nameToken - > isCpp11init ( ) ! = TokenImpl : : Cpp11init : : UNKNOWN )
2019-09-02 20:31:01 +02:00
return nameToken - > isCpp11init ( ) = = TokenImpl : : Cpp11init : : CPP11INIT ;
2017-06-09 22:35:46 +02:00
nameToken = nameToken - > previous ( ) ;
if ( nameToken & & nameToken - > str ( ) = = " , " & & Token : : simpleMatch ( nameToken - > previous ( ) , " } , " ) )
nameToken = nameToken - > linkAt ( - 1 ) ;
}
2015-10-18 16:58:15 +02:00
if ( ! nameToken )
return false ;
2022-10-29 21:24:50 +02:00
if ( nameToken - > str ( ) = = " ) " & & Token : : simpleMatch ( nameToken - > link ( ) - > previous ( ) , " decltype ( " ) & &
! Token : : simpleMatch ( nameToken - > link ( ) - > tokAt ( - 2 ) , " . " ) )
2023-01-18 17:09:55 +01:00
nameToken = nameToken - > link ( ) - > previous ( ) ;
2022-03-23 18:10:33 +01:00
if ( Token : : simpleMatch ( nameToken , " , { " ) )
return true ;
2017-06-09 22:35:46 +02:00
if ( nameToken - > str ( ) = = " > " & & nameToken - > link ( ) )
nameToken = nameToken - > link ( ) - > previous ( ) ;
2023-06-10 07:41:52 +02:00
if ( Token : : Match ( nameToken , " ]|* " ) ) {
const Token * newTok = nameToken - > link ( ) ? nameToken - > link ( ) - > previous ( ) : nameToken - > previous ( ) ;
while ( Token : : Match ( newTok , " %type%|::|* " ) & & ! newTok - > isKeyword ( ) )
2022-04-03 20:05:03 +02:00
newTok = newTok - > previous ( ) ;
if ( Token : : simpleMatch ( newTok , " new " ) )
return true ;
}
2017-04-10 23:05:41 +02:00
2022-10-25 21:50:37 +02:00
auto isCaseStmt = [ ] ( const Token * colonTok ) {
2023-01-26 20:11:45 +01:00
if ( ! Token : : Match ( colonTok - > tokAt ( - 1 ) , " %name%|%num%|%char% : " ) )
2022-10-25 21:50:37 +02:00
return false ;
const Token * caseTok = colonTok - > tokAt ( - 2 ) ;
2022-11-09 21:56:16 +01:00
while ( caseTok & & Token : : Match ( caseTok - > tokAt ( - 1 ) , " ::|%name% " ) )
2022-10-25 21:50:37 +02:00
caseTok = caseTok - > tokAt ( - 1 ) ;
return Token : : simpleMatch ( caseTok , " case " ) ;
} ;
2015-10-18 13:43:39 +02:00
const Token * endtok = nullptr ;
2022-10-25 21:50:37 +02:00
if ( Token : : Match ( nameToken , " %name%|return|: { " ) & & ! isCaseStmt ( nameToken ) & &
2022-01-16 12:35:51 +01:00
( ! Token : : simpleMatch ( nameToken - > tokAt ( 2 ) , " [ " ) | | findLambdaEndScope ( nameToken - > tokAt ( 2 ) ) ) )
2015-10-18 13:43:39 +02:00
endtok = nameToken - > linkAt ( 1 ) ;
else if ( Token : : Match ( nameToken , " %name% < " ) & & Token : : simpleMatch ( nameToken - > linkAt ( 1 ) , " > { " ))
endtok = nameToken - > linkAt ( 1 ) - > linkAt ( 1 ) ;
2022-03-30 19:22:01 +02:00
else if ( Token : : Match ( nameToken - > previous ( ) , " %name%|> ( { " ))
2019-11-19 11:38:03 +01:00
endtok = nameToken - > linkAt ( 1 ) ;
2023-01-18 17:09:55 +01:00
else if ( Token : : simpleMatch ( nameToken , " decltype " ) & & nameToken - > linkAt ( 1 ) )
endtok = nameToken - > linkAt ( 1 ) - > linkAt ( 1 ) ;
2015-10-18 13:43:39 +02:00
else
return false ;
2021-07-22 07:22:26 +02:00
if ( Token : : Match ( nameToken , " else|try|do|const|constexpr|override|volatile|&|&& " ) )
2019-04-15 06:37:27 +02:00
return false ;
#11134 Fix broken AST with (designated) initializers (#4550)
* Make control flow a bit easier, and more similar to previous code
Made similar to around line 790
* In a cpp11init, always parse only the corresponding } (#11134)
- _always_, because in some cases this was omitted (around line 790) or too strict (around line 860)
- _only_, and not following tokens which happen to be } as well (around line 1030)
* Fix unit tests: AST was incorrect, now is fixed
auto var{ {{},{}}, {} };
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-{
| `-{
`-{
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-{
| | `-{
`-{
```
Compare the same example, but with `X{}` instead of just `{}`:
`auto var{ a{b{},c{}}, d{} };`
```
{
|-var
`-,
|-{
| |-a
| `-,
| | |-{
| | | `-b
| | `-{
| | | `-c
`-{
`-d
```
This structure is similar to that of the new AST, not the old AST
* Fix unit tests: another AST was incorrect, now is fixed
Code: `auto var{{1,a::b{2,3}}, {4,a::b{5,6}}};`
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-1 'signed int'
| `-{
| | |-::
| | | |-a
| | | `-b
| | `-,
| | | |-2 'signed int'
| | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-1 'signed int'
| | `-{
| | | |-::
| | | | |-a
| | | | `-b
| | | `-,
| | | | |-2 'signed int'
| | | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
* Fix unit tests: missing ; after class, resulting in incorrectly being marked as cpp11init
Because of the missing `;` after the class declaration, it was marked as a cpp11init block.
Which it isn't, and which now throws an exception
* Fix cpp11init to let unit tests pass again
The following unit tests failed on the newly introduced throws, because the code for these tests incorrectly marked some tokens as cpp11init:
TestVarID::varid_cpp11initialization
TestTokenizer::checkRefQualifiers
* Fix typo
* Improve check for void trailing return type
Observation: the only function body _not_ containing a semicolon, is a void function: something like
auto make_zero(ini& i) -> void {
while(--i > 0) {}
}
Non-void function? Then it must return a value, and thus contain a semicolon, which is checked for a few lines later.
* Fix cpp11init with templated trailing return type
In the following example, vector was marked as cpp11init due to the mismatch of `%any% {`
auto f() -> std::vector<int> { return {}; }
I made the assumption that whenever "%any% {" matches, endtok must be set too.
If this assumtion doesn't hold (so "%any% {" matches, but endtok == nullptr), then the for-loop would search all the way to the end of stream. Which I guess was not the intention.
* Remove comments
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-19 07:25:15 +02:00
if ( Token : : simpleMatch ( nameToken - > previous ( ) , " . void { " ) & & nameToken - > previous ( ) - > originalName ( ) = = " -> " )
return false ; // trailing return type. The only function body that can contain no semicolon is a void function.
2022-11-05 22:41:13 +01:00
if ( Token : : simpleMatch ( nameToken - > previous ( ) , " namespace " ) | | Token : : simpleMatch ( nameToken , " namespace " ) /*anonymous namespace*/ )
2019-06-10 08:22:48 +02:00
return false ;
2023-01-26 22:25:49 +01:00
if ( precedes ( nameToken - > next ( ) , endtok ) & & ! Token : : Match ( nameToken , " return|: " ) ) {
2019-11-27 06:44:43 +01:00
// If there is semicolon between {..} this is not a initlist
for ( const Token * tok2 = nameToken - > next ( ) ; tok2 ! = endtok ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) = = " ; " )
return false ;
2019-12-10 21:21:07 +01:00
const Token * lambdaEnd = findLambdaEndScope ( tok2 ) ;
if ( lambdaEnd )
tok2 = lambdaEnd ;
2019-11-27 06:44:43 +01:00
}
}
2015-10-18 13:43:39 +02:00
// There is no initialisation for example here: 'class Fred {};'
if ( ! Token : : simpleMatch ( endtok , " } ; " ) )
return true ;
const Token * prev = nameToken ;
2023-02-15 19:43:18 +01:00
while ( Token : : Match ( prev , " %name%|::|:|<|>|(|)|,|%num%|%cop%|... " ) ) {
2022-11-12 22:25:05 +01:00
if ( Token : : Match ( prev , " class|struct|union|enum " ) )
2015-10-18 13:43:39 +02:00
return false ;
2015-10-18 16:58:15 +02:00
2015-10-18 13:43:39 +02:00
prev = prev - > previous ( ) ;
}
return true ;
}
2019-12-07 21:06:45 +01:00
static bool isQualifier ( const Token * tok )
2019-12-06 04:19:46 +01:00
{
2019-12-07 21:06:45 +01:00
while ( Token : : Match ( tok , " &|&&|* " ) )
tok = tok - > next ( ) ;
2023-03-17 13:51:55 +01:00
return Token : : Match ( tok , " {|; " ) ;
2019-12-06 04:19:46 +01:00
}
2021-08-07 20:51:18 +02:00
static void compileUnaryOp ( Token * & tok , AST_state & state , void ( * f ) ( Token * & tok , AST_state & state ) )
2012-12-15 20:21:09 +01:00
{
2013-11-04 11:26:16 +01:00
Token * unaryop = tok ;
2014-05-17 12:09:32 +02:00
if ( f ) {
tok = tok - > next ( ) ;
2014-06-04 22:33:08 +02:00
state . depth + + ;
2021-05-06 11:43:15 +02:00
if ( state . depth > AST_MAX_DEPTH )
throw InternalError ( tok , " maximum AST depth exceeded " , InternalError : : AST ) ;
if ( tok )
2014-06-04 22:33:08 +02:00
f ( tok , state ) ;
state . depth - - ;
2014-05-17 12:09:32 +02:00
}
2013-11-04 11:26:16 +01:00
2014-06-04 22:33:08 +02:00
if ( ! state . op . empty ( ) ) {
unaryop - > astOperand1 ( state . op . top ( ) ) ;
state . op . pop ( ) ;
2013-11-04 11:26:16 +01:00
}
2014-06-04 22:33:08 +02:00
state . op . push ( unaryop ) ;
2013-11-04 11:26:16 +01:00
}
2021-08-07 20:51:18 +02:00
static void compileBinOp ( Token * & tok , AST_state & state , void ( * f ) ( Token * & tok , AST_state & state ) )
2013-11-04 11:26:16 +01:00
{
Token * binop = tok ;
2014-05-17 12:09:32 +02:00
if ( f ) {
tok = tok - > next ( ) ;
2021-08-28 22:11:30 +02:00
if ( Token : : Match ( binop , " ::|. ~ " ) )
2021-05-03 20:22:08 +02:00
tok = tok - > next ( ) ;
2014-06-04 22:33:08 +02:00
state . depth + + ;
if ( tok & & state . depth < = AST_MAX_DEPTH )
f ( tok , state ) ;
2023-01-26 20:12:39 +01:00
if ( state . depth > AST_MAX_DEPTH )
throw InternalError ( tok , " maximum AST depth exceeded " , InternalError : : AST ) ;
2014-06-04 22:33:08 +02:00
state . depth - - ;
2014-05-17 12:09:32 +02:00
}
2014-05-03 12:08:42 +02:00
2013-11-04 11:26:16 +01:00
// TODO: Should we check if op is empty.
// * Is it better to add assertion that it isn't?
// * Write debug warning if it's empty?
2014-06-04 22:33:08 +02:00
if ( ! state . op . empty ( ) ) {
binop - > astOperand2 ( state . op . top ( ) ) ;
state . op . pop ( ) ;
2013-11-04 11:26:16 +01:00
}
2014-06-04 22:33:08 +02:00
if ( ! state . op . empty ( ) ) {
binop - > astOperand1 ( state . op . top ( ) ) ;
state . op . pop ( ) ;
2013-11-04 11:26:16 +01:00
}
2014-06-04 22:33:08 +02:00
state . op . push ( binop ) ;
2013-11-04 11:26:16 +01:00
}
2013-03-02 15:49:48 +01:00
2014-06-04 22:33:08 +02:00
static void compileExpression ( Token * & tok , AST_state & state ) ;
2013-11-04 11:26:16 +01:00
2014-06-04 22:33:08 +02:00
static void compileTerm ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2013-11-11 16:39:34 +01:00
if ( ! tok )
return ;
2013-11-20 05:57:56 +01:00
if ( Token : : Match ( tok , " L %str%|%char% " ) )
tok = tok - > next ( ) ;
2017-04-21 21:02:46 +02:00
if ( state . inArrayAssignment & & Token : : Match ( tok - > previous ( ) , " [{,] . %name% " ) ) { // Jump over . in C style struct initialization
state . op . push ( tok ) ;
tok - > astOperand1 ( tok - > next ( ) ) ;
tok = tok - > tokAt ( 2 ) ;
}
2017-04-26 22:35:04 +02:00
if ( state . inArrayAssignment & & Token : : Match ( tok - > previous ( ) , " [{,] [ %num%|%name% ] " ) ) {
2017-04-10 07:25:18 +02:00
state . op . push ( tok ) ;
tok - > astOperand1 ( tok - > next ( ) ) ;
tok = tok - > tokAt ( 3 ) ;
}
2013-11-04 11:26:16 +01:00
if ( tok - > isLiteral ( ) ) {
2014-06-04 22:33:08 +02:00
state . op . push ( tok ) ;
2015-07-27 13:13:30 +02:00
do {
tok = tok - > next ( ) ;
} while ( Token : : Match ( tok , " %name%|%str% " ) ) ;
2017-06-08 15:32:35 +02:00
} else if ( tok - > isName ( ) ) {
2018-03-10 22:30:21 +01:00
if ( Token : : Match ( tok , " return|case " ) | | ( state . cpp & & tok - > str ( ) = = " throw " ) ) {
2017-06-08 15:32:35 +02:00
if ( tok - > str ( ) = = " case " )
state . inCase = true ;
2020-06-14 14:46:16 +02:00
const bool tokIsReturn = tok - > str ( ) = = " return " ;
2020-06-14 18:45:19 +02:00
const bool stopAtColon = state . stopAtColon ;
state . stopAtColon = true ;
2014-06-26 09:03:02 +02:00
compileUnaryOp ( tok , state , compileExpression ) ;
2020-06-14 18:45:19 +02:00
state . stopAtColon = stopAtColon ;
2020-06-14 14:46:16 +02:00
if ( tokIsReturn )
state . op . pop ( ) ;
2018-11-10 21:32:06 +01:00
if ( state . inCase & & Token : : simpleMatch ( tok , " : ; " ) ) {
state . inCase = false ;
2017-06-08 15:32:35 +02:00
tok = tok - > next ( ) ;
2018-11-10 21:32:06 +01:00
}
2015-02-18 19:56:13 +01:00
} else if ( Token : : Match ( tok , " sizeof !!( " ) ) {
compileUnaryOp ( tok , state , compileExpression ) ;
state . op . pop ( ) ;
2021-08-07 20:51:18 +02:00
} else if ( state . cpp & & findCppTypeInitPar ( tok ) ) { // int(0), int*(123), ..
2017-05-24 20:18:31 +02:00
tok = findCppTypeInitPar ( tok ) ;
state . op . push ( tok ) ;
tok = tok - > tokAt ( 2 ) ;
2015-10-18 13:43:39 +02:00
} else if ( state . cpp & & iscpp11init ( tok ) ) { // X{} X<Y>{} etc
2015-10-17 17:03:24 +02:00
state . op . push ( tok ) ;
tok = tok - > next ( ) ;
2015-10-18 13:43:39 +02:00
if ( tok - > str ( ) = = " < " )
tok = tok - > link ( ) - > next ( ) ;
2020-09-27 20:41:09 +02:00
2020-04-20 08:59:35 +02:00
if ( Token : : Match ( tok , " { . %name% =|{ " ) ) {
#11134 Fix broken AST with (designated) initializers (#4550)
* Make control flow a bit easier, and more similar to previous code
Made similar to around line 790
* In a cpp11init, always parse only the corresponding } (#11134)
- _always_, because in some cases this was omitted (around line 790) or too strict (around line 860)
- _only_, and not following tokens which happen to be } as well (around line 1030)
* Fix unit tests: AST was incorrect, now is fixed
auto var{ {{},{}}, {} };
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-{
| `-{
`-{
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-{
| | `-{
`-{
```
Compare the same example, but with `X{}` instead of just `{}`:
`auto var{ a{b{},c{}}, d{} };`
```
{
|-var
`-,
|-{
| |-a
| `-,
| | |-{
| | | `-b
| | `-{
| | | `-c
`-{
`-d
```
This structure is similar to that of the new AST, not the old AST
* Fix unit tests: another AST was incorrect, now is fixed
Code: `auto var{{1,a::b{2,3}}, {4,a::b{5,6}}};`
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-1 'signed int'
| `-{
| | |-::
| | | |-a
| | | `-b
| | `-,
| | | |-2 'signed int'
| | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-1 'signed int'
| | `-{
| | | |-::
| | | | |-a
| | | | `-b
| | | `-,
| | | | |-2 'signed int'
| | | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
* Fix unit tests: missing ; after class, resulting in incorrectly being marked as cpp11init
Because of the missing `;` after the class declaration, it was marked as a cpp11init block.
Which it isn't, and which now throws an exception
* Fix cpp11init to let unit tests pass again
The following unit tests failed on the newly introduced throws, because the code for these tests incorrectly marked some tokens as cpp11init:
TestVarID::varid_cpp11initialization
TestTokenizer::checkRefQualifiers
* Fix typo
* Improve check for void trailing return type
Observation: the only function body _not_ containing a semicolon, is a void function: something like
auto make_zero(ini& i) -> void {
while(--i > 0) {}
}
Non-void function? Then it must return a value, and thus contain a semicolon, which is checked for a few lines later.
* Fix cpp11init with templated trailing return type
In the following example, vector was marked as cpp11init due to the mismatch of `%any% {`
auto f() -> std::vector<int> { return {}; }
I made the assumption that whenever "%any% {" matches, endtok must be set too.
If this assumtion doesn't hold (so "%any% {" matches, but endtok == nullptr), then the for-loop would search all the way to the end of stream. Which I guess was not the intention.
* Remove comments
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-19 07:25:15 +02:00
const Token * end = tok - > link ( ) ;
2019-07-17 10:14:00 +02:00
const int inArrayAssignment = state . inArrayAssignment ;
state . inArrayAssignment = 1 ;
2019-05-04 19:05:03 +02:00
compileBinOp ( tok , state , compileExpression ) ;
state . inArrayAssignment = inArrayAssignment ;
#11134 Fix broken AST with (designated) initializers (#4550)
* Make control flow a bit easier, and more similar to previous code
Made similar to around line 790
* In a cpp11init, always parse only the corresponding } (#11134)
- _always_, because in some cases this was omitted (around line 790) or too strict (around line 860)
- _only_, and not following tokens which happen to be } as well (around line 1030)
* Fix unit tests: AST was incorrect, now is fixed
auto var{ {{},{}}, {} };
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-{
| `-{
`-{
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-{
| | `-{
`-{
```
Compare the same example, but with `X{}` instead of just `{}`:
`auto var{ a{b{},c{}}, d{} };`
```
{
|-var
`-,
|-{
| |-a
| `-,
| | |-{
| | | `-b
| | `-{
| | | `-c
`-{
`-d
```
This structure is similar to that of the new AST, not the old AST
* Fix unit tests: another AST was incorrect, now is fixed
Code: `auto var{{1,a::b{2,3}}, {4,a::b{5,6}}};`
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-1 'signed int'
| `-{
| | |-::
| | | |-a
| | | `-b
| | `-,
| | | |-2 'signed int'
| | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-1 'signed int'
| | `-{
| | | |-::
| | | | |-a
| | | | `-b
| | | `-,
| | | | |-2 'signed int'
| | | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
* Fix unit tests: missing ; after class, resulting in incorrectly being marked as cpp11init
Because of the missing `;` after the class declaration, it was marked as a cpp11init block.
Which it isn't, and which now throws an exception
* Fix cpp11init to let unit tests pass again
The following unit tests failed on the newly introduced throws, because the code for these tests incorrectly marked some tokens as cpp11init:
TestVarID::varid_cpp11initialization
TestTokenizer::checkRefQualifiers
* Fix typo
* Improve check for void trailing return type
Observation: the only function body _not_ containing a semicolon, is a void function: something like
auto make_zero(ini& i) -> void {
while(--i > 0) {}
}
Non-void function? Then it must return a value, and thus contain a semicolon, which is checked for a few lines later.
* Fix cpp11init with templated trailing return type
In the following example, vector was marked as cpp11init due to the mismatch of `%any% {`
auto f() -> std::vector<int> { return {}; }
I made the assumption that whenever "%any% {" matches, endtok must be set too.
If this assumtion doesn't hold (so "%any% {" matches, but endtok == nullptr), then the for-loop would search all the way to the end of stream. Which I guess was not the intention.
* Remove comments
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-19 07:25:15 +02:00
if ( tok = = end )
tok = tok - > next ( ) ;
else
throw InternalError ( tok , " Syntax error. Unexpected tokens in designated initializer. " , InternalError : : AST ) ;
2019-05-04 19:05:03 +02:00
}
2015-01-31 10:50:39 +01:00
} else if ( ! state . cpp | | ! Token : : Match ( tok , " new|delete %name%|*|&|::|(|[ " ) ) {
2022-02-22 06:30:17 +01:00
std : : vector < Token * > inner ;
tok = skipDecl ( tok , & inner ) ;
for ( Token * tok3 : inner ) {
2022-01-22 07:22:57 +01:00
AST_state state1 ( state . cpp ) ;
compileExpression ( tok3 , state1 ) ;
}
2020-09-14 18:44:50 +02:00
bool repeat = true ;
2020-09-20 20:14:30 +02:00
while ( repeat ) {
2020-09-14 18:44:50 +02:00
repeat = false ;
if ( Token : : Match ( tok - > next ( ) , " %name% " ) ) {
tok = tok - > next ( ) ;
repeat = true ;
}
if ( Token : : simpleMatch ( tok - > next ( ) , " < " ) & & Token : : Match ( tok - > linkAt ( 1 ) , " > %name% " ) ) {
tok = tok - > next ( ) - > link ( ) - > next ( ) ;
repeat = true ;
}
}
2014-06-26 09:03:02 +02:00
state . op . push ( tok ) ;
2015-07-27 13:13:30 +02:00
if ( Token : : Match ( tok , " %name% < " ) & & tok - > linkAt ( 1 ) )
2014-06-26 09:03:02 +02:00
tok = tok - > linkAt ( 1 ) ;
2022-03-28 22:05:41 +02:00
else if ( Token : : Match ( tok , " %name% ... " ) | | ( state . op . size ( ) = = 1 & & state . depth = = 0 & & Token : : Match ( tok - > tokAt ( - 3 ) , " !!& ) ( %name% ) = " ) ) )
2019-09-04 08:07:30 +02:00
tok = tok - > next ( ) ;
2013-11-04 11:26:16 +01:00
tok = tok - > next ( ) ;
2015-07-27 13:13:30 +02:00
if ( Token : : Match ( tok , " %str% " ) ) {
while ( Token : : Match ( tok , " %name%|%str% " ) )
tok = tok - > next ( ) ;
}
2020-01-04 10:45:24 +01:00
if ( Token : : Match ( tok , " %name% %assign% " ) )
tok = tok - > next ( ) ;
2014-06-26 09:03:02 +02:00
}
2014-02-05 06:05:48 +01:00
} else if ( tok - > str ( ) = = " { " ) {
2017-04-21 17:44:11 +02:00
const Token * prev = tok - > previous ( ) ;
2020-11-15 10:37:29 +01:00
if ( Token : : simpleMatch ( prev , " ) { " ) & & iscast ( prev - > link ( ) , state . cpp ) )
2017-04-21 17:44:11 +02:00
prev = prev - > link ( ) - > previous ( ) ;
2017-04-10 22:17:34 +02:00
if ( Token : : simpleMatch ( tok - > link ( ) , " } [ " ) ) {
tok = tok - > next ( ) ;
2023-06-05 20:43:17 +02:00
} else if ( ( state . cpp & & iscpp11init ( tok ) ) | | Token : : simpleMatch ( tok - > previous ( ) , " ] { " )) {
#11134 Fix broken AST with (designated) initializers (#4550)
* Make control flow a bit easier, and more similar to previous code
Made similar to around line 790
* In a cpp11init, always parse only the corresponding } (#11134)
- _always_, because in some cases this was omitted (around line 790) or too strict (around line 860)
- _only_, and not following tokens which happen to be } as well (around line 1030)
* Fix unit tests: AST was incorrect, now is fixed
auto var{ {{},{}}, {} };
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-{
| `-{
`-{
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-{
| | `-{
`-{
```
Compare the same example, but with `X{}` instead of just `{}`:
`auto var{ a{b{},c{}}, d{} };`
```
{
|-var
`-,
|-{
| |-a
| `-,
| | |-{
| | | `-b
| | `-{
| | | `-c
`-{
`-d
```
This structure is similar to that of the new AST, not the old AST
* Fix unit tests: another AST was incorrect, now is fixed
Code: `auto var{{1,a::b{2,3}}, {4,a::b{5,6}}};`
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-1 'signed int'
| `-{
| | |-::
| | | |-a
| | | `-b
| | `-,
| | | |-2 'signed int'
| | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-1 'signed int'
| | `-{
| | | |-::
| | | | |-a
| | | | `-b
| | | `-,
| | | | |-2 'signed int'
| | | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
* Fix unit tests: missing ; after class, resulting in incorrectly being marked as cpp11init
Because of the missing `;` after the class declaration, it was marked as a cpp11init block.
Which it isn't, and which now throws an exception
* Fix cpp11init to let unit tests pass again
The following unit tests failed on the newly introduced throws, because the code for these tests incorrectly marked some tokens as cpp11init:
TestVarID::varid_cpp11initialization
TestTokenizer::checkRefQualifiers
* Fix typo
* Improve check for void trailing return type
Observation: the only function body _not_ containing a semicolon, is a void function: something like
auto make_zero(ini& i) -> void {
while(--i > 0) {}
}
Non-void function? Then it must return a value, and thus contain a semicolon, which is checked for a few lines later.
* Fix cpp11init with templated trailing return type
In the following example, vector was marked as cpp11init due to the mismatch of `%any% {`
auto f() -> std::vector<int> { return {}; }
I made the assumption that whenever "%any% {" matches, endtok must be set too.
If this assumtion doesn't hold (so "%any% {" matches, but endtok == nullptr), then the for-loop would search all the way to the end of stream. Which I guess was not the intention.
* Remove comments
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-19 07:25:15 +02:00
Token * const end = tok - > link ( ) ;
2020-09-27 20:41:09 +02:00
if ( state . op . empty ( ) | | Token : : Match ( tok - > previous ( ) , " [{,] " ) | | Token : : Match ( tok - > tokAt ( - 2 ) , " %name% ( " ) ) {
#11134 Fix broken AST with (designated) initializers (#4550)
* Make control flow a bit easier, and more similar to previous code
Made similar to around line 790
* In a cpp11init, always parse only the corresponding } (#11134)
- _always_, because in some cases this was omitted (around line 790) or too strict (around line 860)
- _only_, and not following tokens which happen to be } as well (around line 1030)
* Fix unit tests: AST was incorrect, now is fixed
auto var{ {{},{}}, {} };
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-{
| `-{
`-{
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-{
| | `-{
`-{
```
Compare the same example, but with `X{}` instead of just `{}`:
`auto var{ a{b{},c{}}, d{} };`
```
{
|-var
`-,
|-{
| |-a
| `-,
| | |-{
| | | `-b
| | `-{
| | | `-c
`-{
`-d
```
This structure is similar to that of the new AST, not the old AST
* Fix unit tests: another AST was incorrect, now is fixed
Code: `auto var{{1,a::b{2,3}}, {4,a::b{5,6}}};`
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-1 'signed int'
| `-{
| | |-::
| | | |-a
| | | `-b
| | `-,
| | | |-2 'signed int'
| | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-1 'signed int'
| | `-{
| | | |-::
| | | | |-a
| | | | `-b
| | | `-,
| | | | |-2 'signed int'
| | | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
* Fix unit tests: missing ; after class, resulting in incorrectly being marked as cpp11init
Because of the missing `;` after the class declaration, it was marked as a cpp11init block.
Which it isn't, and which now throws an exception
* Fix cpp11init to let unit tests pass again
The following unit tests failed on the newly introduced throws, because the code for these tests incorrectly marked some tokens as cpp11init:
TestVarID::varid_cpp11initialization
TestTokenizer::checkRefQualifiers
* Fix typo
* Improve check for void trailing return type
Observation: the only function body _not_ containing a semicolon, is a void function: something like
auto make_zero(ini& i) -> void {
while(--i > 0) {}
}
Non-void function? Then it must return a value, and thus contain a semicolon, which is checked for a few lines later.
* Fix cpp11init with templated trailing return type
In the following example, vector was marked as cpp11init due to the mismatch of `%any% {`
auto f() -> std::vector<int> { return {}; }
I made the assumption that whenever "%any% {" matches, endtok must be set too.
If this assumtion doesn't hold (so "%any% {" matches, but endtok == nullptr), then the for-loop would search all the way to the end of stream. Which I guess was not the intention.
* Remove comments
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-19 07:25:15 +02:00
if ( Token : : Match ( tok , " { . %name% =|{ " ) ) {
const int inArrayAssignment = state . inArrayAssignment ;
state . inArrayAssignment = 1 ;
compileBinOp ( tok , state , compileExpression ) ;
state . inArrayAssignment = inArrayAssignment ;
} else if ( Token : : simpleMatch ( tok , " { } " ) ) {
2020-09-27 20:41:09 +02:00
state . op . push ( tok ) ;
#11134 Fix broken AST with (designated) initializers (#4550)
* Make control flow a bit easier, and more similar to previous code
Made similar to around line 790
* In a cpp11init, always parse only the corresponding } (#11134)
- _always_, because in some cases this was omitted (around line 790) or too strict (around line 860)
- _only_, and not following tokens which happen to be } as well (around line 1030)
* Fix unit tests: AST was incorrect, now is fixed
auto var{ {{},{}}, {} };
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-{
| `-{
`-{
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-{
| | `-{
`-{
```
Compare the same example, but with `X{}` instead of just `{}`:
`auto var{ a{b{},c{}}, d{} };`
```
{
|-var
`-,
|-{
| |-a
| `-,
| | |-{
| | | `-b
| | `-{
| | | `-c
`-{
`-d
```
This structure is similar to that of the new AST, not the old AST
* Fix unit tests: another AST was incorrect, now is fixed
Code: `auto var{{1,a::b{2,3}}, {4,a::b{5,6}}};`
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-1 'signed int'
| `-{
| | |-::
| | | |-a
| | | `-b
| | `-,
| | | |-2 'signed int'
| | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-1 'signed int'
| | `-{
| | | |-::
| | | | |-a
| | | | `-b
| | | `-,
| | | | |-2 'signed int'
| | | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
* Fix unit tests: missing ; after class, resulting in incorrectly being marked as cpp11init
Because of the missing `;` after the class declaration, it was marked as a cpp11init block.
Which it isn't, and which now throws an exception
* Fix cpp11init to let unit tests pass again
The following unit tests failed on the newly introduced throws, because the code for these tests incorrectly marked some tokens as cpp11init:
TestVarID::varid_cpp11initialization
TestTokenizer::checkRefQualifiers
* Fix typo
* Improve check for void trailing return type
Observation: the only function body _not_ containing a semicolon, is a void function: something like
auto make_zero(ini& i) -> void {
while(--i > 0) {}
}
Non-void function? Then it must return a value, and thus contain a semicolon, which is checked for a few lines later.
* Fix cpp11init with templated trailing return type
In the following example, vector was marked as cpp11init due to the mismatch of `%any% {`
auto f() -> std::vector<int> { return {}; }
I made the assumption that whenever "%any% {" matches, endtok must be set too.
If this assumtion doesn't hold (so "%any% {" matches, but endtok == nullptr), then the for-loop would search all the way to the end of stream. Which I guess was not the intention.
* Remove comments
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-19 07:25:15 +02:00
tok = tok - > next ( ) ;
} else {
compileUnaryOp ( tok , state , compileExpression ) ;
if ( precedes ( tok , end ) ) // typically for something like `MACRO(x, { if (c) { ... } })`, where end is the last curly, and tok is the open curly for the if
tok = end ;
2020-09-27 20:41:09 +02:00
}
} else
2017-06-09 22:35:46 +02:00
compileBinOp ( tok , state , compileExpression ) ;
#11134 Fix broken AST with (designated) initializers (#4550)
* Make control flow a bit easier, and more similar to previous code
Made similar to around line 790
* In a cpp11init, always parse only the corresponding } (#11134)
- _always_, because in some cases this was omitted (around line 790) or too strict (around line 860)
- _only_, and not following tokens which happen to be } as well (around line 1030)
* Fix unit tests: AST was incorrect, now is fixed
auto var{ {{},{}}, {} };
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-{
| `-{
`-{
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-{
| | `-{
`-{
```
Compare the same example, but with `X{}` instead of just `{}`:
`auto var{ a{b{},c{}}, d{} };`
```
{
|-var
`-,
|-{
| |-a
| `-,
| | |-{
| | | `-b
| | `-{
| | | `-c
`-{
`-d
```
This structure is similar to that of the new AST, not the old AST
* Fix unit tests: another AST was incorrect, now is fixed
Code: `auto var{{1,a::b{2,3}}, {4,a::b{5,6}}};`
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-1 'signed int'
| `-{
| | |-::
| | | |-a
| | | `-b
| | `-,
| | | |-2 'signed int'
| | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-1 'signed int'
| | `-{
| | | |-::
| | | | |-a
| | | | `-b
| | | `-,
| | | | |-2 'signed int'
| | | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
* Fix unit tests: missing ; after class, resulting in incorrectly being marked as cpp11init
Because of the missing `;` after the class declaration, it was marked as a cpp11init block.
Which it isn't, and which now throws an exception
* Fix cpp11init to let unit tests pass again
The following unit tests failed on the newly introduced throws, because the code for these tests incorrectly marked some tokens as cpp11init:
TestVarID::varid_cpp11initialization
TestTokenizer::checkRefQualifiers
* Fix typo
* Improve check for void trailing return type
Observation: the only function body _not_ containing a semicolon, is a void function: something like
auto make_zero(ini& i) -> void {
while(--i > 0) {}
}
Non-void function? Then it must return a value, and thus contain a semicolon, which is checked for a few lines later.
* Fix cpp11init with templated trailing return type
In the following example, vector was marked as cpp11init due to the mismatch of `%any% {`
auto f() -> std::vector<int> { return {}; }
I made the assumption that whenever "%any% {" matches, endtok must be set too.
If this assumtion doesn't hold (so "%any% {" matches, but endtok == nullptr), then the for-loop would search all the way to the end of stream. Which I guess was not the intention.
* Remove comments
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-19 07:25:15 +02:00
if ( tok ! = end )
throw InternalError ( tok , " Syntax error. Unexpected tokens in initializer. " , InternalError : : AST ) ;
if ( tok - > next ( ) )
2017-06-09 22:35:46 +02:00
tok = tok - > next ( ) ;
2019-11-23 21:36:36 +01:00
} else if ( state . cpp & & Token : : Match ( tok - > tokAt ( - 2 ) , " %name% ( { " ) && !Token::findsimplematch(tok, " ; " , tok->link())) {
2019-10-27 12:00:08 +01:00
if ( Token : : simpleMatch ( tok , " { } " ) )
tok = tok - > tokAt ( 2 ) ;
else {
Token * tok1 = tok ;
state . inArrayAssignment + + ;
compileUnaryOp ( tok , state , compileExpression ) ;
state . inArrayAssignment - - ;
tok = tok1 - > link ( ) - > next ( ) ;
}
2017-04-21 21:02:46 +02:00
} else if ( ! state . inArrayAssignment & & ! Token : : simpleMatch ( prev , " = " ) ) {
2014-07-31 23:14:44 +02:00
state . op . push ( tok ) ;
tok = tok - > link ( ) - > next ( ) ;
} else {
if ( tok - > link ( ) ! = tok - > next ( ) ) {
state . inArrayAssignment + + ;
compileUnaryOp ( tok , state , compileExpression ) ;
2020-12-02 07:38:21 +01:00
if ( Token : : Match ( tok , " } [,};] " ) & & state . inArrayAssignment > 0 ) {
2015-07-21 11:40:42 +02:00
tok = tok - > next ( ) ;
state . inArrayAssignment - - ;
}
2014-07-31 23:14:44 +02:00
} else {
state . op . push ( tok ) ;
2017-04-09 22:06:13 +02:00
tok = tok - > tokAt ( 2 ) ;
2014-07-31 23:14:44 +02:00
}
}
2012-12-15 20:21:09 +01:00
}
2013-11-04 11:26:16 +01:00
}
2012-12-15 20:21:09 +01:00
2014-06-04 22:33:08 +02:00
static void compileScope ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileTerm ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " :: " ) {
2021-05-03 20:22:08 +02:00
const Token * lastOp = state . op . empty ( ) ? nullptr : state . op . top ( ) ;
2021-05-03 20:33:03 +02:00
if ( Token : : Match ( lastOp , " :: %name% " ) )
lastOp = lastOp - > next ( ) ;
2021-05-03 20:22:08 +02:00
if ( Token : : Match ( lastOp , " %name% " ) & &
( lastOp - > next ( ) = = tok | | ( Token : : Match ( lastOp , " %name% < " ) & & lastOp - > linkAt ( 1 ) & & tok = = lastOp - > linkAt ( 1 ) - > next ( ) ) ) )
compileBinOp ( tok , state , compileTerm ) ;
2014-02-25 06:36:10 +01:00
else
2021-05-03 20:22:08 +02:00
compileUnaryOp ( tok , state , compileTerm ) ;
2013-11-04 11:26:16 +01:00
} else break ;
2012-12-16 10:06:55 +01:00
}
2013-11-04 11:26:16 +01:00
}
2014-06-04 22:33:08 +02:00
static bool isPrefixUnary ( const Token * tok , bool cpp )
2013-11-25 20:58:40 +01:00
{
2023-06-05 20:43:17 +02:00
if ( cpp & & Token : : simpleMatch ( tok - > previous ( ) , " * [ " ) & & Token : : simpleMatch ( tok - > link ( ) , " ] { " ) ) {
for ( const Token * prev = tok - > previous ( ) ; Token : : Match ( prev , " %name%|::|*|&|>|>> " ) ; prev = prev - > previous ( ) ) {
if ( Token : : Match ( prev , " >|>> " ) ) {
if ( ! prev - > link ( ) )
break ;
prev = prev - > link ( ) ;
}
if ( prev - > str ( ) = = " new " )
return false ;
}
}
2014-05-17 12:09:32 +02:00
if ( ! tok - > previous ( )
2023-02-24 06:31:20 +01:00
| | ( ( Token : : Match ( tok - > previous ( ) , " (|[|{|%op%|;|?|:|,|.|return|:: " ) | | ( cpp & & tok - > strAt ( - 1 ) = = " throw " ) )
2015-08-14 20:46:13 +02:00
& & ( tok - > previous ( ) - > tokType ( ) ! = Token : : eIncDecOp | | tok - > tokType ( ) = = Token : : eIncDecOp ) ) )
2014-05-17 12:09:32 +02:00
return true ;
2023-02-24 06:31:20 +01:00
if ( tok - > previous ( ) - > str ( ) = = " } " ) {
const Token * parent = tok - > linkAt ( - 1 ) - > tokAt ( - 1 ) ;
return ! Token : : Match ( parent , " %type% " ) | | parent - > isKeyword ( ) ;
}
2018-09-27 19:26:08 +02:00
if ( tok - > str ( ) = = " * " & & tok - > previous ( ) - > tokType ( ) = = Token : : eIncDecOp & & isPrefixUnary ( tok - > previous ( ) , cpp ) )
return true ;
2020-11-15 10:37:29 +01:00
return tok - > strAt ( - 1 ) = = " ) " & & iscast ( tok - > linkAt ( - 1 ) , cpp ) ;
2014-05-08 06:48:53 +02:00
}
2014-06-04 22:33:08 +02:00
static void compilePrecedence2 ( Token * & tok , AST_state & state )
2014-05-08 06:48:53 +02:00
{
2022-09-26 22:05:58 +02:00
auto doCompileScope = [ & ] ( const Token * tok ) - > bool {
const bool isStartOfCpp11Init = state . cpp & & tok & & tok - > str ( ) = = " { " & & iscpp11init ( tok ) ;
2023-06-10 07:41:52 +02:00
if ( isStartOfCpp11Init | | Token : : simpleMatch ( tok , " ( " ) ) {
2022-09-26 22:05:58 +02:00
tok = tok - > previous ( ) ;
2023-06-10 07:41:52 +02:00
while ( Token : : simpleMatch ( tok , " * " ) )
tok = tok - > previous ( ) ;
2022-09-26 22:05:58 +02:00
while ( tok & & Token : : Match ( tok - > previous ( ) , " :: %type% " ) )
tok = tok - > tokAt ( - 2 ) ;
if ( tok & & ! tok - > isKeyword ( ) )
tok = tok - > previous ( ) ;
return ! Token : : Match ( tok , " new ::| %type% " ) ;
}
2023-03-13 16:30:27 +01:00
return ! findLambdaEndTokenWithoutAST ( tok ) ;
2022-09-26 22:05:58 +02:00
} ;
2023-06-10 07:41:52 +02:00
bool isNew = true ;
if ( doCompileScope ( tok ) ) {
2022-03-24 20:08:51 +01:00
compileScope ( tok , state ) ;
2023-06-10 07:41:52 +02:00
isNew = false ;
}
2014-05-08 06:48:53 +02:00
while ( tok ) {
2015-08-14 20:46:13 +02:00
if ( tok - > tokType ( ) = = Token : : eIncDecOp & & ! isPrefixUnary ( tok , state . cpp ) ) {
2014-06-04 22:33:08 +02:00
compileUnaryOp ( tok , state , compileScope ) ;
2019-09-04 08:07:30 +02:00
} else if ( tok - > str ( ) = = " ... " ) {
2023-06-07 20:46:14 +02:00
if ( ! Token : : simpleMatch ( tok - > previous ( ) , " ) " ) )
state . op . push ( tok ) ;
2019-09-09 21:35:49 +02:00
tok = tok - > next ( ) ;
2019-09-04 08:07:30 +02:00
break ;
2014-05-19 21:54:59 +02:00
} else if ( tok - > str ( ) = = " . " & & tok - > strAt ( 1 ) ! = " * " ) {
2014-06-04 18:08:51 +02:00
if ( tok - > strAt ( 1 ) = = " . " ) {
2014-06-04 22:33:08 +02:00
state . op . push ( tok ) ;
2014-06-04 18:08:51 +02:00
tok = tok - > tokAt ( 3 ) ;
break ;
2021-08-28 22:11:30 +02:00
}
compileBinOp ( tok , state , compileScope ) ;
2014-05-08 06:48:53 +02:00
} else if ( tok - > str ( ) = = " [ " ) {
2023-06-27 16:19:12 +02:00
if ( state . cpp & & isPrefixUnary ( tok , state . cpp ) & & Token : : Match ( tok - > link ( ) , " ] (|{|< " ) ) { // Lambda
2014-05-25 19:48:31 +02:00
// What we do here:
// - Nest the round bracket under the square bracket.
// - Nest what follows the lambda (if anything) with the lambda opening [
2015-06-17 19:32:44 +02:00
// - Compile the content of the lambda function as separate tree (this is done later)
2016-11-27 11:40:42 +01:00
// this must be consistent with isLambdaCaptureList
2017-04-09 17:49:55 +02:00
Token * const squareBracket = tok ;
2020-09-05 07:56:01 +02:00
// Parse arguments in the capture list
if ( tok - > strAt ( 1 ) ! = " ] " ) {
Token * tok2 = tok - > next ( ) ;
AST_state state2 ( state . cpp ) ;
compileExpression ( tok2 , state2 ) ;
if ( ! state2 . op . empty ( ) ) {
squareBracket - > astOperand2 ( state2 . op . top ( ) ) ;
}
}
2023-06-27 16:19:12 +02:00
const bool hasTemplateArg = Token : : simpleMatch ( squareBracket - > link ( ) , " ] < " ) & &
Token : : simpleMatch ( squareBracket - > link ( ) - > next ( ) - > link ( ) , " > ( " ) ;
if ( Token : : simpleMatch ( squareBracket - > link ( ) , " ] ( " ) | | hasTemplateArg ) {
Token * const roundBracket = hasTemplateArg ? squareBracket - > link ( ) - > next ( ) - > link ( ) - > next ( ) : squareBracket - > link ( ) - > next ( ) ;
2017-04-09 17:49:55 +02:00
Token * curlyBracket = roundBracket - > link ( ) - > next ( ) ;
#11134 Fix broken AST with (designated) initializers (#4550)
* Make control flow a bit easier, and more similar to previous code
Made similar to around line 790
* In a cpp11init, always parse only the corresponding } (#11134)
- _always_, because in some cases this was omitted (around line 790) or too strict (around line 860)
- _only_, and not following tokens which happen to be } as well (around line 1030)
* Fix unit tests: AST was incorrect, now is fixed
auto var{ {{},{}}, {} };
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-{
| `-{
`-{
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-{
| | `-{
`-{
```
Compare the same example, but with `X{}` instead of just `{}`:
`auto var{ a{b{},c{}}, d{} };`
```
{
|-var
`-,
|-{
| |-a
| `-,
| | |-{
| | | `-b
| | `-{
| | | `-c
`-{
`-d
```
This structure is similar to that of the new AST, not the old AST
* Fix unit tests: another AST was incorrect, now is fixed
Code: `auto var{{1,a::b{2,3}}, {4,a::b{5,6}}};`
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-1 'signed int'
| `-{
| | |-::
| | | |-a
| | | `-b
| | `-,
| | | |-2 'signed int'
| | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-1 'signed int'
| | `-{
| | | |-::
| | | | |-a
| | | | `-b
| | | `-,
| | | | |-2 'signed int'
| | | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
* Fix unit tests: missing ; after class, resulting in incorrectly being marked as cpp11init
Because of the missing `;` after the class declaration, it was marked as a cpp11init block.
Which it isn't, and which now throws an exception
* Fix cpp11init to let unit tests pass again
The following unit tests failed on the newly introduced throws, because the code for these tests incorrectly marked some tokens as cpp11init:
TestVarID::varid_cpp11initialization
TestTokenizer::checkRefQualifiers
* Fix typo
* Improve check for void trailing return type
Observation: the only function body _not_ containing a semicolon, is a void function: something like
auto make_zero(ini& i) -> void {
while(--i > 0) {}
}
Non-void function? Then it must return a value, and thus contain a semicolon, which is checked for a few lines later.
* Fix cpp11init with templated trailing return type
In the following example, vector was marked as cpp11init due to the mismatch of `%any% {`
auto f() -> std::vector<int> { return {}; }
I made the assumption that whenever "%any% {" matches, endtok must be set too.
If this assumtion doesn't hold (so "%any% {" matches, but endtok == nullptr), then the for-loop would search all the way to the end of stream. Which I guess was not the intention.
* Remove comments
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-19 07:25:15 +02:00
while ( Token : : Match ( curlyBracket , " mutable|const|constexpr|consteval " ) )
2018-10-31 12:36:08 +01:00
curlyBracket = curlyBracket - > next ( ) ;
2022-11-12 22:25:05 +01:00
if ( Token : : simpleMatch ( curlyBracket , " noexcept " ) ) {
if ( Token : : simpleMatch ( curlyBracket - > next ( ) , " ( " ) )
curlyBracket = curlyBracket - > linkAt ( 1 ) - > next ( ) ;
else
curlyBracket = curlyBracket - > next ( ) ;
}
2020-11-28 06:53:46 +01:00
if ( curlyBracket & & curlyBracket - > originalName ( ) = = " -> " )
2019-12-16 12:17:01 +01:00
curlyBracket = findTypeEnd ( curlyBracket - > next ( ) ) ;
2017-04-09 17:49:55 +02:00
if ( curlyBracket & & curlyBracket - > str ( ) = = " { " ) {
squareBracket - > astOperand1 ( roundBracket ) ;
roundBracket - > astOperand1 ( curlyBracket ) ;
state . op . push ( squareBracket ) ;
tok = curlyBracket - > link ( ) - > next ( ) ;
continue ;
}
} else {
Token * const curlyBracket = squareBracket - > link ( ) - > next ( ) ;
squareBracket - > astOperand1 ( curlyBracket ) ;
2015-10-20 23:55:29 +02:00
state . op . push ( squareBracket ) ;
tok = curlyBracket - > link ( ) - > next ( ) ;
2017-04-09 17:49:55 +02:00
continue ;
2015-10-20 23:55:29 +02:00
}
}
2017-04-09 17:49:55 +02:00
2023-05-02 06:55:31 +02:00
Token * const tok2 = tok ;
2023-06-05 20:43:17 +02:00
if ( tok - > strAt ( 1 ) ! = " ] " ) {
2017-04-09 17:49:55 +02:00
compileBinOp ( tok , state , compileExpression ) ;
2023-06-05 20:43:17 +02:00
if ( Token : : Match ( tok2 - > previous ( ) , " %type%|* [ " ) & & Token : : Match ( tok , " ] { !!} " ) ) {
tok = tok - > next ( ) ;
Token * const tok3 = tok ;
compileBinOp ( tok , state , compileExpression ) ;
if ( tok ! = tok3 - > link ( ) )
throw InternalError ( tok , " Syntax error in {..} " , InternalError : : AST ) ;
tok = tok - > next ( ) ;
continue ;
}
}
2017-04-09 17:49:55 +02:00
else
compileUnaryOp ( tok , state , compileExpression ) ;
tok = tok2 - > link ( ) - > next ( ) ;
2023-06-09 22:31:14 +02:00
} else if ( Token : : simpleMatch ( tok , " ( { " ) & & Token : : simpleMatch ( tok - > linkAt ( 1 ) - > previous ( ) , " ; } ) " ) && !Token::Match(tok->previous(), " % name % ( " )) {
state . op . push ( tok - > next ( ) ) ;
tok = tok - > link ( ) - > next ( ) ;
continue ;
2020-11-15 10:37:29 +01:00
} else if ( tok - > str ( ) = = " ( " & & ( ! iscast ( tok , state . cpp ) | | Token : : Match ( tok - > previous ( ) , " if|while|for|switch|catch " ) ) ) {
2014-05-17 12:09:32 +02:00
Token * tok2 = tok ;
2014-04-29 06:09:26 +02:00
tok = tok - > next ( ) ;
2015-05-25 08:20:14 +02:00
const bool opPrevTopSquare = ! state . op . empty ( ) & & state . op . top ( ) & & state . op . top ( ) - > str ( ) = = " [ " ;
const std : : size_t oldOpSize = state . op . size ( ) ;
2014-06-04 22:33:08 +02:00
compileExpression ( tok , state ) ;
2014-05-17 12:09:32 +02:00
tok = tok2 ;
2023-06-10 07:41:52 +02:00
if ( ( oldOpSize > 0 & & ( isNew | | Token : : simpleMatch ( tok - > previous ( ) , " } ( " ) ) )
2020-02-16 13:58:43 +01:00
| | ( tok - > previous ( ) & & tok - > previous ( ) - > isName ( ) & & ! Token : : Match ( tok - > previous ( ) , " return|case " ) & & ( ! state . cpp | | ! Token : : Match ( tok - > previous ( ) , " throw|delete " ) ) )
2014-06-04 22:33:08 +02:00
| | ( tok - > strAt ( - 1 ) = = " ] " & & ( ! state . cpp | | ! Token : : Match ( tok - > linkAt ( - 1 ) - > previous ( ) , " new|delete " ) ) )
2014-05-17 12:09:32 +02:00
| | ( tok - > strAt ( - 1 ) = = " > " & & tok - > linkAt ( - 1 ) )
2020-11-15 10:37:29 +01:00
| | ( tok - > strAt ( - 1 ) = = " ) " & & ! iscast ( tok - > linkAt ( - 1 ) , state . cpp ) ) // Don't treat brackets to clarify precedence as function calls
2014-05-25 19:48:31 +02:00
| | ( tok - > strAt ( - 1 ) = = " } " & & opPrevTopSquare ) ) {
2014-07-10 09:23:14 +02:00
const bool operandInside = oldOpSize < state . op . size ( ) ;
2014-06-04 18:08:51 +02:00
if ( operandInside )
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , nullptr ) ;
2014-05-17 12:09:32 +02:00
else
2014-06-04 22:33:08 +02:00
compileUnaryOp ( tok , state , nullptr ) ;
2014-05-17 12:09:32 +02:00
}
tok = tok - > link ( ) - > next ( ) ;
2020-11-15 10:37:29 +01:00
} else if ( iscast ( tok , state . cpp ) & & Token : : simpleMatch ( tok - > link ( ) , " ) { " ) && Token::simpleMatch(tok->link()->linkAt(1), " } [ " )) {
2019-10-06 09:43:46 +02:00
Token * cast = tok ;
tok = tok - > link ( ) - > next ( ) ;
Token * tok1 = tok ;
compileUnaryOp ( tok , state , compileExpression ) ;
cast - > astOperand1 ( tok1 ) ;
tok = tok1 - > link ( ) - > next ( ) ;
2015-10-18 16:58:15 +02:00
} else if ( state . cpp & & tok - > str ( ) = = " { " && iscpp11init(tok)) {
2023-02-08 21:07:16 +01:00
Token * end = tok - > link ( ) ;
2015-10-18 16:58:15 +02:00
if ( Token : : simpleMatch ( tok , " { } " ) )
#11134 Fix broken AST with (designated) initializers (#4550)
* Make control flow a bit easier, and more similar to previous code
Made similar to around line 790
* In a cpp11init, always parse only the corresponding } (#11134)
- _always_, because in some cases this was omitted (around line 790) or too strict (around line 860)
- _only_, and not following tokens which happen to be } as well (around line 1030)
* Fix unit tests: AST was incorrect, now is fixed
auto var{ {{},{}}, {} };
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-{
| `-{
`-{
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-{
| | `-{
`-{
```
Compare the same example, but with `X{}` instead of just `{}`:
`auto var{ a{b{},c{}}, d{} };`
```
{
|-var
`-,
|-{
| |-a
| `-,
| | |-{
| | | `-b
| | `-{
| | | `-c
`-{
`-d
```
This structure is similar to that of the new AST, not the old AST
* Fix unit tests: another AST was incorrect, now is fixed
Code: `auto var{{1,a::b{2,3}}, {4,a::b{5,6}}};`
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-1 'signed int'
| `-{
| | |-::
| | | |-a
| | | `-b
| | `-,
| | | |-2 'signed int'
| | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-1 'signed int'
| | `-{
| | | |-::
| | | | |-a
| | | | `-b
| | | `-,
| | | | |-2 'signed int'
| | | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
* Fix unit tests: missing ; after class, resulting in incorrectly being marked as cpp11init
Because of the missing `;` after the class declaration, it was marked as a cpp11init block.
Which it isn't, and which now throws an exception
* Fix cpp11init to let unit tests pass again
The following unit tests failed on the newly introduced throws, because the code for these tests incorrectly marked some tokens as cpp11init:
TestVarID::varid_cpp11initialization
TestTokenizer::checkRefQualifiers
* Fix typo
* Improve check for void trailing return type
Observation: the only function body _not_ containing a semicolon, is a void function: something like
auto make_zero(ini& i) -> void {
while(--i > 0) {}
}
Non-void function? Then it must return a value, and thus contain a semicolon, which is checked for a few lines later.
* Fix cpp11init with templated trailing return type
In the following example, vector was marked as cpp11init due to the mismatch of `%any% {`
auto f() -> std::vector<int> { return {}; }
I made the assumption that whenever "%any% {" matches, endtok must be set too.
If this assumtion doesn't hold (so "%any% {" matches, but endtok == nullptr), then the for-loop would search all the way to the end of stream. Which I guess was not the intention.
* Remove comments
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-19 07:25:15 +02:00
{
compileUnaryOp ( tok , state , nullptr ) ;
tok = tok - > next ( ) ;
}
2015-10-18 16:58:15 +02:00
else
#11134 Fix broken AST with (designated) initializers (#4550)
* Make control flow a bit easier, and more similar to previous code
Made similar to around line 790
* In a cpp11init, always parse only the corresponding } (#11134)
- _always_, because in some cases this was omitted (around line 790) or too strict (around line 860)
- _only_, and not following tokens which happen to be } as well (around line 1030)
* Fix unit tests: AST was incorrect, now is fixed
auto var{ {{},{}}, {} };
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-{
| `-{
`-{
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-{
| | `-{
`-{
```
Compare the same example, but with `X{}` instead of just `{}`:
`auto var{ a{b{},c{}}, d{} };`
```
{
|-var
`-,
|-{
| |-a
| `-,
| | |-{
| | | `-b
| | `-{
| | | `-c
`-{
`-d
```
This structure is similar to that of the new AST, not the old AST
* Fix unit tests: another AST was incorrect, now is fixed
Code: `auto var{{1,a::b{2,3}}, {4,a::b{5,6}}};`
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-1 'signed int'
| `-{
| | |-::
| | | |-a
| | | `-b
| | `-,
| | | |-2 'signed int'
| | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-1 'signed int'
| | `-{
| | | |-::
| | | | |-a
| | | | `-b
| | | `-,
| | | | |-2 'signed int'
| | | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
* Fix unit tests: missing ; after class, resulting in incorrectly being marked as cpp11init
Because of the missing `;` after the class declaration, it was marked as a cpp11init block.
Which it isn't, and which now throws an exception
* Fix cpp11init to let unit tests pass again
The following unit tests failed on the newly introduced throws, because the code for these tests incorrectly marked some tokens as cpp11init:
TestVarID::varid_cpp11initialization
TestTokenizer::checkRefQualifiers
* Fix typo
* Improve check for void trailing return type
Observation: the only function body _not_ containing a semicolon, is a void function: something like
auto make_zero(ini& i) -> void {
while(--i > 0) {}
}
Non-void function? Then it must return a value, and thus contain a semicolon, which is checked for a few lines later.
* Fix cpp11init with templated trailing return type
In the following example, vector was marked as cpp11init due to the mismatch of `%any% {`
auto f() -> std::vector<int> { return {}; }
I made the assumption that whenever "%any% {" matches, endtok must be set too.
If this assumtion doesn't hold (so "%any% {" matches, but endtok == nullptr), then the for-loop would search all the way to the end of stream. Which I guess was not the intention.
* Remove comments
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-19 07:25:15 +02:00
{
2015-10-18 16:58:15 +02:00
compileBinOp ( tok , state , compileExpression ) ;
#11134 Fix broken AST with (designated) initializers (#4550)
* Make control flow a bit easier, and more similar to previous code
Made similar to around line 790
* In a cpp11init, always parse only the corresponding } (#11134)
- _always_, because in some cases this was omitted (around line 790) or too strict (around line 860)
- _only_, and not following tokens which happen to be } as well (around line 1030)
* Fix unit tests: AST was incorrect, now is fixed
auto var{ {{},{}}, {} };
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-{
| `-{
`-{
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-{
| | `-{
`-{
```
Compare the same example, but with `X{}` instead of just `{}`:
`auto var{ a{b{},c{}}, d{} };`
```
{
|-var
`-,
|-{
| |-a
| `-,
| | |-{
| | | `-b
| | `-{
| | | `-c
`-{
`-d
```
This structure is similar to that of the new AST, not the old AST
* Fix unit tests: another AST was incorrect, now is fixed
Code: `auto var{{1,a::b{2,3}}, {4,a::b{5,6}}};`
Old AST:
```
{
|-var
`-{
`-,
|-,
| |-1 'signed int'
| `-{
| | |-::
| | | |-a
| | | `-b
| | `-,
| | | |-2 'signed int'
| | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
New AST:
```
{
|-var
`-,
|-{
| `-,
| | |-1 'signed int'
| | `-{
| | | |-::
| | | | |-a
| | | | `-b
| | | `-,
| | | | |-2 'signed int'
| | | | `-3 'signed int'
`-{
`-,
|-4 'signed int'
`-{
|-::
| |-a
| `-b
`-,
|-5 'signed int'
`-6 'signed int'
```
* Fix unit tests: missing ; after class, resulting in incorrectly being marked as cpp11init
Because of the missing `;` after the class declaration, it was marked as a cpp11init block.
Which it isn't, and which now throws an exception
* Fix cpp11init to let unit tests pass again
The following unit tests failed on the newly introduced throws, because the code for these tests incorrectly marked some tokens as cpp11init:
TestVarID::varid_cpp11initialization
TestTokenizer::checkRefQualifiers
* Fix typo
* Improve check for void trailing return type
Observation: the only function body _not_ containing a semicolon, is a void function: something like
auto make_zero(ini& i) -> void {
while(--i > 0) {}
}
Non-void function? Then it must return a value, and thus contain a semicolon, which is checked for a few lines later.
* Fix cpp11init with templated trailing return type
In the following example, vector was marked as cpp11init due to the mismatch of `%any% {`
auto f() -> std::vector<int> { return {}; }
I made the assumption that whenever "%any% {" matches, endtok must be set too.
If this assumtion doesn't hold (so "%any% {" matches, but endtok == nullptr), then the for-loop would search all the way to the end of stream. Which I guess was not the intention.
* Remove comments
Co-authored-by: Gerbo Engels <gerbo.engels@ortec-finance.com>
2022-10-19 07:25:15 +02:00
}
if ( tok = = end )
tok = end - > next ( ) ;
else
throw InternalError ( tok , " Syntax error. Unexpected tokens in initializer. " , InternalError : : AST ) ;
2013-11-25 20:58:40 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compilePrecedence3 ( Token * & tok , AST_state & state )
2014-05-17 12:09:32 +02:00
{
2014-06-04 22:33:08 +02:00
compilePrecedence2 ( tok , state ) ;
2014-05-17 12:09:32 +02:00
while ( tok ) {
2015-08-14 20:46:13 +02:00
if ( ( Token : : Match ( tok , " [+-!~*&] " ) | | tok - > tokType ( ) = = Token : : eIncDecOp ) & &
2014-06-04 22:33:08 +02:00
isPrefixUnary ( tok , state . cpp ) ) {
2014-06-04 18:08:51 +02:00
if ( Token : : Match ( tok , " * [*,)] " ) ) {
2015-08-16 14:22:46 +02:00
Token * tok2 = tok - > next ( ) ;
2014-06-04 18:08:51 +02:00
while ( tok2 - > next ( ) & & tok2 - > str ( ) = = " * " )
tok2 = tok2 - > next ( ) ;
if ( Token : : Match ( tok2 , " [>),] " ) ) {
tok = tok2 ;
continue ;
}
}
2014-06-04 22:33:08 +02:00
compileUnaryOp ( tok , state , compilePrecedence3 ) ;
2020-11-15 10:37:29 +01:00
} else if ( tok - > str ( ) = = " ( " & & iscast ( tok , state . cpp ) ) {
2018-11-14 21:05:03 +01:00
Token * castTok = tok ;
2019-02-10 19:00:01 +01:00
castTok - > isCast ( true ) ;
2014-05-17 12:09:32 +02:00
tok = tok - > link ( ) - > next ( ) ;
2020-03-08 16:21:22 +01:00
const int inArrayAssignment = state . inArrayAssignment ;
2020-03-08 16:45:51 +01:00
if ( tok & & tok - > str ( ) = = " { " )
2020-03-08 16:21:22 +01:00
state . inArrayAssignment = 1 ;
2018-11-14 21:05:03 +01:00
compilePrecedence3 ( tok , state ) ;
2020-03-08 16:21:22 +01:00
state . inArrayAssignment = inArrayAssignment ;
2018-11-14 21:05:03 +01:00
compileUnaryOp ( castTok , state , nullptr ) ;
2015-01-31 10:50:39 +01:00
} else if ( state . cpp & & Token : : Match ( tok , " new %name%|::|( " ) ) {
2014-10-11 08:32:49 +02:00
Token * newtok = tok ;
2014-06-04 18:08:51 +02:00
tok = tok - > next ( ) ;
2014-10-12 12:13:01 +02:00
bool innertype = false ;
2014-10-11 11:27:13 +02:00
if ( tok - > str ( ) = = " ( " ) {
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( tok , " ( &| %name% " ) & & Token : : Match ( tok - > link ( ) , " ) ( %type% " ) & & Token : : simpleMatch ( tok - > link ( ) - > linkAt ( 1 ) , " ) ( " ) )
2014-10-11 11:27:13 +02:00
tok = tok - > link ( ) - > next ( ) ;
2020-11-23 22:03:50 +01:00
if ( Token : : Match ( tok - > link ( ) , " ) ::| %type% " ) ) {
if ( Token : : Match ( tok , " ( !!) " ) ) {
Token * innerTok = tok - > next ( ) ;
AST_state innerState ( true ) ;
compileExpression ( innerTok , innerState ) ;
}
2014-10-11 11:27:13 +02:00
tok = tok - > link ( ) - > next ( ) ;
2020-11-23 22:03:50 +01:00
} else if ( Token : : Match ( tok , " ( %type% " ) & & Token : : Match ( tok - > link ( ) , " ) [() ; , [ ] " )) {
2014-10-11 11:27:13 +02:00
tok = tok - > next ( ) ;
2014-10-12 12:13:01 +02:00
innertype = true ;
2015-01-31 10:50:39 +01:00
} else if ( Token : : Match ( tok , " ( &| %name% " ) & & Token : : simpleMatch ( tok - > link ( ) , " ) ( " ) ) {
2014-10-11 13:20:48 +02:00
tok = tok - > next ( ) ;
2014-10-12 12:13:01 +02:00
innertype = true ;
2014-10-13 19:12:20 +02:00
} else {
/* bad code */
continue ;
2014-10-12 12:13:01 +02:00
}
2014-10-11 11:27:13 +02:00
}
2020-05-18 19:31:13 +02:00
Token * leftToken = tok ;
2022-09-26 22:05:58 +02:00
if ( Token : : simpleMatch ( tok , " :: " ) ) {
tok - > astOperand1 ( tok - > next ( ) ) ;
tok = tok - > next ( ) ;
}
else {
while ( Token : : Match ( tok - > next ( ) , " :: %name% " ) ) {
Token * scopeToken = tok - > next ( ) ; //The ::
scopeToken - > astOperand1 ( leftToken ) ;
scopeToken - > astOperand2 ( scopeToken - > next ( ) ) ;
leftToken = scopeToken ;
tok = scopeToken - > next ( ) ;
}
2020-05-18 19:31:13 +02:00
}
2014-06-04 22:33:08 +02:00
state . op . push ( tok ) ;
2015-01-31 10:50:39 +01:00
while ( Token : : Match ( tok , " %name%|*|&|<|:: " ) ) {
2014-06-04 18:08:51 +02:00
if ( tok - > link ( ) )
tok = tok - > link ( ) ;
tok = tok - > next ( ) ;
}
2014-10-10 19:05:31 +02:00
if ( Token : : Match ( tok , " ( const| %type% ) ( " ) ) {
2014-10-10 12:47:01 +02:00
state . op . push ( tok - > next ( ) ) ;
2014-10-10 19:05:31 +02:00
tok = tok - > link ( ) - > next ( ) ;
2014-10-10 12:47:01 +02:00
compileBinOp ( tok , state , compilePrecedence2 ) ;
2023-06-05 20:43:17 +02:00
} else if ( Token : : Match ( tok , " (|{|[ " ) )
2014-09-29 10:26:15 +02:00
compilePrecedence2 ( tok , state ) ;
2014-10-12 12:57:01 +02:00
else if ( innertype & & Token : : simpleMatch ( tok , " ) [ " )) {
tok = tok - > next ( ) ;
compilePrecedence2 ( tok , state ) ;
}
2014-10-11 08:32:49 +02:00
compileUnaryOp ( newtok , state , nullptr ) ;
2014-10-12 12:13:01 +02:00
if ( innertype & & Token : : simpleMatch ( tok , " ) , " ) )
2014-10-12 10:20:03 +02:00
tok = tok - > next ( ) ;
2015-01-31 10:50:39 +01:00
} else if ( state . cpp & & Token : : Match ( tok , " delete %name%|*|&|::|(|[ " ) ) {
2014-06-04 18:08:51 +02:00
Token * tok2 = tok ;
tok = tok - > next ( ) ;
2015-05-27 21:39:31 +02:00
if ( tok & & tok - > str ( ) = = " [ " )
2014-06-04 18:08:51 +02:00
tok = tok - > link ( ) - > next ( ) ;
2014-06-04 22:33:08 +02:00
compilePrecedence3 ( tok , state ) ;
compileUnaryOp ( tok2 , state , nullptr ) ;
2014-05-17 12:09:32 +02:00
}
2014-06-04 18:08:51 +02:00
// TODO: Handle sizeof
2014-05-17 12:09:32 +02:00
else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compilePointerToElem ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compilePrecedence3 ( tok , state ) ;
2014-05-19 21:54:59 +02:00
while ( tok ) {
if ( Token : : simpleMatch ( tok , " . * " ) ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compilePrecedence3 ) ;
2014-05-19 21:54:59 +02:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileMulDiv ( Token * & tok , AST_state & state )
2014-05-19 21:54:59 +02:00
{
2014-06-04 22:33:08 +02:00
compilePointerToElem ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
2019-12-07 21:06:45 +01:00
if ( Token : : Match ( tok , " [/%] " ) | | ( tok - > str ( ) = = " * " & & ! tok - > astOperand1 ( ) & & ! isQualifier ( tok ) ) ) {
2014-04-26 13:32:08 +02:00
if ( Token : : Match ( tok , " * [*,)] " ) ) {
2015-08-16 14:22:46 +02:00
Token * tok2 = tok - > next ( ) ;
2014-05-17 12:09:32 +02:00
while ( tok2 - > next ( ) & & tok2 - > str ( ) = = " * " )
tok2 = tok2 - > next ( ) ;
2014-06-04 18:08:51 +02:00
if ( Token : : Match ( tok2 , " [>),] " ) ) {
tok = tok2 ;
2014-05-17 12:09:32 +02:00
break ;
}
2014-04-26 13:32:08 +02:00
}
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compilePointerToElem ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileAddSub ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileMulDiv ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
2014-05-24 19:04:47 +02:00
if ( Token : : Match ( tok , " +|- " ) & & ! tok - > astOperand1 ( ) ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileMulDiv ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileShift ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileAddSub ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( Token : : Match ( tok , " <<|>> " ) ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileAddSub ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2021-04-22 19:15:22 +02:00
static void compileThreewayComp ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileShift ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
2021-04-22 19:15:22 +02:00
if ( tok - > str ( ) = = " <=> " ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileShift ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2012-12-16 10:06:55 +01:00
2021-04-22 19:15:22 +02:00
static void compileRelComp ( Token * & tok , AST_state & state )
{
compileThreewayComp ( tok , state ) ;
while ( tok ) {
if ( Token : : Match ( tok , " <|<=|>=|> " ) & & ! tok - > link ( ) ) {
compileBinOp ( tok , state , compileThreewayComp ) ;
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileEqComp ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileRelComp ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( Token : : Match ( tok , " ==|!= " ) ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileRelComp ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileAnd ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileEqComp ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
2019-12-07 21:06:45 +01:00
if ( tok - > str ( ) = = " & " & & ! tok - > astOperand1 ( ) & & ! isQualifier ( tok ) ) {
2014-06-04 18:08:51 +02:00
Token * tok2 = tok - > next ( ) ;
2014-09-28 22:05:05 +02:00
if ( ! tok2 )
break ;
2014-06-04 18:08:51 +02:00
if ( tok2 - > str ( ) = = " & " )
tok2 = tok2 - > next ( ) ;
2014-09-14 11:26:16 +02:00
if ( state . cpp & & Token : : Match ( tok2 , " ,|) " ) ) {
2014-06-04 18:08:51 +02:00
tok = tok2 ;
break ; // rValue reference
}
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileEqComp ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileXor ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileAnd ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " ^ " ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileAnd ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileOr ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileXor ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " | " ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileXor ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileLogicAnd ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileOr ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
2019-12-07 21:06:45 +01:00
if ( tok - > str ( ) = = " && " & & ! isQualifier ( tok ) ) {
2019-10-04 12:30:11 +02:00
if ( ! tok - > astOperand1 ( ) ) {
Token * tok2 = tok - > next ( ) ;
if ( ! tok2 )
break ;
if ( state . cpp & & Token : : Match ( tok2 , " ,|) " ) ) {
tok = tok2 ;
break ; // rValue reference
}
}
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileOr ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileLogicOr ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileLogicAnd ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " || " ) {
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileLogicAnd ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileAssignTernary ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileLogicOr ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
2015-07-24 13:02:00 +02:00
if ( tok - > isAssignmentOp ( ) ) {
state . assign + + ;
2021-06-30 21:40:45 +02:00
const Token * tok1 = tok - > next ( ) ;
2015-07-24 13:02:00 +02:00
compileBinOp ( tok , state , compileAssignTernary ) ;
2021-06-30 21:40:45 +02:00
if ( Token : : simpleMatch ( tok1 , " { " ) & & tok = = tok1 - > link ( ) & & tok - > next ( ) )
tok = tok - > next ( ) ;
2019-07-17 10:14:00 +02:00
if ( state . assign > 0 )
2015-07-24 13:02:00 +02:00
state . assign - - ;
} else if ( tok - > str ( ) = = " ? " ) {
2015-10-12 18:14:56 +02:00
// http://en.cppreference.com/w/cpp/language/operator_precedence says about ternary operator:
// "The expression in the middle of the conditional operator (between ? and :) is parsed as if parenthesized: its precedence relative to ?: is ignored."
2015-12-25 09:51:08 +01:00
// Hence, we rely on Tokenizer::prepareTernaryOpForAST() to add such parentheses where necessary.
2020-06-14 18:45:19 +02:00
const bool stopAtColon = state . stopAtColon ;
state . stopAtColon = false ;
2015-07-24 13:02:00 +02:00
if ( tok - > strAt ( 1 ) = = " : " ) {
2017-08-09 20:00:26 +02:00
state . op . push ( nullptr ) ;
2014-05-19 21:54:59 +02:00
}
2019-07-17 10:14:00 +02:00
const int assign = state . assign ;
state . assign = 0 ;
2015-07-24 13:02:00 +02:00
compileBinOp ( tok , state , compileAssignTernary ) ;
state . assign = assign ;
2020-06-14 18:45:19 +02:00
state . stopAtColon = stopAtColon ;
2015-07-24 13:02:00 +02:00
} else if ( tok - > str ( ) = = " : " ) {
2018-11-10 21:32:06 +01:00
if ( state . depth = = 1U & & state . inCase ) {
state . inCase = false ;
tok = tok - > next ( ) ;
2017-06-08 15:32:35 +02:00
break ;
2018-11-10 21:32:06 +01:00
}
2020-06-14 18:45:19 +02:00
if ( state . stopAtColon )
break ;
2019-07-17 10:14:00 +02:00
if ( state . assign > 0 )
2015-07-24 13:02:00 +02:00
break ;
2014-06-04 22:33:08 +02:00
compileBinOp ( tok , state , compileAssignTernary ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileComma ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
compileAssignTernary ( tok , state ) ;
2013-11-04 11:26:16 +01:00
while ( tok ) {
if ( tok - > str ( ) = = " , " ) {
2017-04-22 11:23:11 +02:00
if ( Token : : simpleMatch ( tok , " , } " ) )
tok = tok - > next ( ) ;
else
compileBinOp ( tok , state , compileAssignTernary ) ;
2019-11-01 09:05:45 +01:00
} else if ( tok - > str ( ) = = " ; " && state.functionCallEndPar && tok->index() < state.functionCallEndPar->index()) {
compileBinOp ( tok , state , compileAssignTernary ) ;
2013-11-04 11:26:16 +01:00
} else break ;
}
}
2014-06-04 22:33:08 +02:00
static void compileExpression ( Token * & tok , AST_state & state )
2013-11-04 11:26:16 +01:00
{
2014-06-04 22:33:08 +02:00
if ( state . depth > AST_MAX_DEPTH )
2021-05-06 11:43:15 +02:00
throw InternalError ( tok , " maximum AST depth exceeded " , InternalError : : AST ) ; // ticket #5592
2013-11-10 15:51:33 +01:00
if ( tok )
2014-06-04 22:33:08 +02:00
compileComma ( tok , state ) ;
2013-11-04 11:26:16 +01:00
}
2022-11-13 21:20:44 +01:00
const Token * isLambdaCaptureList ( const Token * tok )
2016-11-20 15:14:49 +01:00
{
// a lambda expression '[x](y){}' is compiled as:
// [
2017-04-09 17:49:55 +02:00
// `-( <<-- optional
2016-11-20 15:14:49 +01:00
// `-{
// see compilePrecedence2
2022-11-13 21:20:44 +01:00
if ( ! Token : : simpleMatch ( tok , " [ " ) )
return nullptr ;
2017-04-10 23:29:15 +02:00
if ( ! Token : : Match ( tok - > link ( ) , " ] (|{ " ) )
2022-11-13 21:20:44 +01:00
return nullptr ;
2017-04-10 23:29:15 +02:00
if ( Token : : simpleMatch ( tok - > astOperand1 ( ) , " { " ) & & tok - > astOperand1 ( ) = = tok - > link ( ) - > next ( ) )
2022-11-13 21:20:44 +01:00
return tok - > astOperand1 ( ) ;
2016-11-20 15:14:49 +01:00
if ( ! tok - > astOperand1 ( ) | | tok - > astOperand1 ( ) - > str ( ) ! = " ( " )
2022-11-13 21:20:44 +01:00
return nullptr ;
2016-11-20 15:14:49 +01:00
const Token * params = tok - > astOperand1 ( ) ;
2022-11-13 21:20:44 +01:00
if ( ! Token : : simpleMatch ( params - > astOperand1 ( ) , " { " ) )
return nullptr ;
return params - > astOperand1 ( ) ;
2016-11-20 15:14:49 +01:00
}
2023-03-13 16:30:27 +01:00
const Token * findLambdaEndTokenWithoutAST ( const Token * tok ) {
if ( ! ( Token : : simpleMatch ( tok , " [ " ) & & tok - > link ( ) ) )
return nullptr ;
tok = tok - > link ( ) - > next ( ) ;
if ( Token : : simpleMatch ( tok , " ( " ) & & tok - > link ( ) )
tok = tok - > link ( ) - > next ( ) ;
if ( ! ( Token : : simpleMatch ( tok , " { " ) & & tok - > link ( ) ) )
return nullptr ;
return tok - > link ( ) - > next ( ) ;
}
2022-12-18 16:55:55 +01:00
static Token * createAstAtToken ( Token * tok , bool cpp ) ;
2017-03-19 07:26:11 +01:00
// Compile inner expressions inside inner ({..}) and lambda bodies
static void createAstAtTokenInner ( Token * const tok1 , const Token * endToken , bool cpp )
{
2021-07-09 07:22:24 +02:00
for ( Token * tok = tok1 ; precedes ( tok , endToken ) ; tok = tok ? tok - > next ( ) : nullptr ) {
2020-09-07 10:54:32 +02:00
if ( tok - > str ( ) = = " { " & & ! iscpp11init ( tok ) ) {
const Token * const endToken2 = tok - > link ( ) ;
2021-06-24 08:25:13 +02:00
bool hasAst = false ;
for ( const Token * inner = tok - > next ( ) ; inner ! = endToken2 ; inner = inner - > next ( ) ) {
if ( inner - > astOperand1 ( ) ) {
hasAst = true ;
break ;
}
if ( tok - > isConstOp ( ) )
break ;
if ( inner - > str ( ) = = " { " )
inner = inner - > link ( ) ;
}
if ( ! hasAst ) {
for ( ; tok & & tok ! = endToken & & tok ! = endToken2 ; tok = tok ? tok - > next ( ) : nullptr )
tok = createAstAtToken ( tok , cpp ) ;
}
2019-10-22 18:39:44 +02:00
} else if ( cpp & & tok - > str ( ) = = " [ " ) {
2017-03-19 07:26:11 +01:00
if ( isLambdaCaptureList ( tok ) ) {
2019-06-16 10:09:38 +02:00
tok = tok - > astOperand1 ( ) ;
2017-04-09 17:49:55 +02:00
if ( tok - > str ( ) = = " ( " )
2019-06-16 10:09:38 +02:00
tok = tok - > astOperand1 ( ) ;
2017-03-19 07:26:11 +01:00
const Token * const endToken2 = tok - > link ( ) ;
2021-05-04 20:15:44 +02:00
tok = tok - > next ( ) ;
2017-03-19 07:26:11 +01:00
for ( ; tok & & tok ! = endToken & & tok ! = endToken2 ; tok = tok ? tok - > next ( ) : nullptr )
tok = createAstAtToken ( tok , cpp ) ;
}
}
2022-05-10 22:47:57 +02:00
else if ( Token : : simpleMatch ( tok , " ( * ) [ " )) {
bool hasAst = false ;
for ( const Token * tok2 = tok - > linkAt ( 3 ) ; tok2 ! = tok ; tok2 = tok2 - > previous ( ) ) {
if ( tok2 - > astParent ( ) | | tok2 - > astOperand1 ( ) | | tok2 - > astOperand2 ( ) ) {
hasAst = true ;
break ;
}
}
if ( ! hasAst ) {
Token * const startTok = tok = tok - > tokAt ( 4 ) ;
const Token * const endtok = startTok - > linkAt ( - 1 ) ;
AST_state state ( cpp ) ;
compileExpression ( tok , state ) ;
createAstAtTokenInner ( startTok , endtok , cpp ) ;
}
}
2017-03-19 07:26:11 +01:00
}
}
2023-05-04 11:10:58 +02:00
static Token * findAstTop ( Token * tok1 , const Token * tok2 )
2017-04-17 22:16:02 +02:00
{
2017-04-17 21:11:53 +02:00
for ( Token * tok = tok1 ; tok & & ( tok ! = tok2 ) ; tok = tok - > next ( ) ) {
2019-11-03 11:02:59 +01:00
if ( tok - > astParent ( ) | | tok - > astOperand1 ( ) | | tok - > astOperand2 ( ) ) {
while ( tok - > astParent ( ) & & tok - > astParent ( ) - > index ( ) > = tok1 - > index ( ) & & tok - > astParent ( ) - > index ( ) < = tok2 - > index ( ) )
tok = tok - > astParent ( ) ;
return tok ;
}
2017-04-17 21:11:53 +02:00
if ( Token : : simpleMatch ( tok , " ( { " ) )
tok = tok - > link ( ) ;
}
for ( Token * tok = tok1 ; tok & & ( tok ! = tok2 ) ; tok = tok - > next ( ) ) {
if ( tok - > isName ( ) | | tok - > isNumber ( ) )
return tok ;
if ( Token : : simpleMatch ( tok , " ( { " ) )
tok = tok - > link ( ) ;
}
return nullptr ;
}
2014-06-04 22:33:08 +02:00
static Token * createAstAtToken ( Token * tok , bool cpp )
2014-01-27 06:18:42 +01:00
{
2023-03-02 20:08:22 +01:00
// skip function pointer declaration
2023-03-04 11:09:42 +01:00
if ( Token : : Match ( tok , " %type% " ) & & ! Token : : Match ( tok , " return|throw|if|while|new|delete " ) ) {
2023-05-02 06:55:31 +02:00
Token * type = tok ;
2023-03-02 20:08:22 +01:00
while ( Token : : Match ( type , " %type%|*|&|< " ) ) {
if ( type - > str ( ) = = " < " ) {
if ( type - > link ( ) )
type = type - > link ( ) ;
else
break ;
}
type = type - > next ( ) ;
}
2023-03-04 11:09:42 +01:00
if ( Token : : Match ( type , " ( * *| %var% " ) & &
Token : : Match ( type - > link ( ) - > previous ( ) , " %var%|] ) ( " ) & &
2023-03-02 20:08:22 +01:00
Token : : Match ( type - > link ( ) - > linkAt ( 1 ) , " ) [;,)] " ) )
return type - > link ( ) - > linkAt ( 1 ) - > next ( ) ;
}
2015-10-12 18:14:56 +02:00
if ( Token : : simpleMatch ( tok , " for ( " ) ) {
2020-02-27 09:58:41 +01:00
if ( cpp & & Token : : Match ( tok , " for ( const| auto &|&&| [ " ) ) {
Token * decl = Token : : findsimplematch ( tok , " [ " ) ;
if ( Token : : simpleMatch ( decl - > link ( ) , " ] : " ) ) {
AST_state state1 ( cpp ) ;
2020-02-27 10:51:34 +01:00
while ( decl - > str ( ) ! = " ] " ) {
2020-02-27 09:58:41 +01:00
if ( Token : : Match ( decl , " %name% ,|] " ) ) {
state1 . op . push ( decl ) ;
} else if ( decl - > str ( ) = = " , " ) {
if ( ! state1 . op . empty ( ) ) {
decl - > astOperand1 ( state1 . op . top ( ) ) ;
state1 . op . pop ( ) ;
}
if ( ! state1 . op . empty ( ) ) {
state1 . op . top ( ) - > astOperand2 ( decl ) ;
state1 . op . pop ( ) ;
}
state1 . op . push ( decl ) ;
}
decl = decl - > next ( ) ;
}
if ( state1 . op . size ( ) > 1 ) {
Token * lastName = state1 . op . top ( ) ;
state1 . op . pop ( ) ;
state1 . op . top ( ) - > astOperand2 ( lastName ) ;
}
decl = decl - > next ( ) ;
Token * colon = decl ;
compileExpression ( decl , state1 ) ;
tok - > next ( ) - > astOperand1 ( tok ) ;
tok - > next ( ) - > astOperand2 ( colon ) ;
return decl ;
}
}
2022-02-22 06:30:17 +01:00
std : : vector < Token * > inner ;
Token * tok2 = skipDecl ( tok - > tokAt ( 2 ) , & inner ) ;
for ( Token * tok3 : inner ) {
2022-01-20 21:36:48 +01:00
AST_state state1 ( cpp ) ;
compileExpression ( tok3 , state1 ) ;
}
2014-02-16 11:47:52 +01:00
Token * init1 = nullptr ;
2015-10-18 11:42:18 +02:00
Token * const endPar = tok - > next ( ) - > link ( ) ;
2020-06-09 20:57:00 +02:00
if ( tok2 = = tok - > tokAt ( 2 ) & & Token : : Match ( tok2 , " %op%|( " ) ) {
init1 = tok2 ;
AST_state state1 ( cpp ) ;
compileExpression ( tok2 , state1 ) ;
2020-09-26 19:22:24 +02:00
if ( Token : : Match ( init1 , " ( !!{ " ) ) {
2020-07-19 11:10:38 +02:00
for ( Token * tok3 = init1 ; tok3 ! = tok3 - > link ( ) ; tok3 = tok3 - > next ( ) ) {
if ( tok3 - > astParent ( ) ) {
while ( tok3 - > astParent ( ) )
tok3 = tok3 - > astParent ( ) ;
init1 = tok3 ;
break ;
}
if ( ! Token : : Match ( tok3 , " %op%|(|[ " ) )
init1 = tok3 ;
}
}
2020-06-09 20:57:00 +02:00
} else {
while ( tok2 & & tok2 ! = endPar & & tok2 - > str ( ) ! = " ; " ) {
if ( tok2 - > str ( ) = = " < " & & tok2 - > link ( ) ) {
tok2 = tok2 - > link ( ) ;
2022-03-24 22:07:21 +01:00
} else if ( Token : : Match ( tok2 , " %name% ) | % op % | ( | [ | . | : | : : " ) || Token::Match(tok2->previous(), " [ ( ; { } ] % cop % | ( " )) {
2020-06-09 20:57:00 +02:00
init1 = tok2 ;
AST_state state1 ( cpp ) ;
compileExpression ( tok2 , state1 ) ;
if ( Token : : Match ( tok2 , " ;|) " ) )
break ;
2021-01-09 20:32:38 +01:00
init1 = nullptr ;
2020-06-09 20:57:00 +02:00
}
if ( ! tok2 ) // #7109 invalid code
return nullptr ;
tok2 = tok2 - > next ( ) ;
2014-01-15 17:32:14 +01:00
}
2014-01-27 06:18:42 +01:00
}
if ( ! tok2 | | tok2 - > str ( ) ! = " ; " ) {
if ( tok2 = = endPar & & init1 ) {
2022-09-29 13:29:50 +02:00
createAstAtTokenInner ( init1 - > next ( ) , endPar , cpp ) ;
2014-01-27 06:18:42 +01:00
tok - > next ( ) - > astOperand2 ( init1 ) ;
tok - > next ( ) - > astOperand1 ( tok ) ;
2014-01-15 17:32:14 +01:00
}
2014-01-27 06:18:42 +01:00
return tok2 ;
}
2014-01-15 17:32:14 +01:00
2014-01-27 06:18:42 +01:00
Token * const init = init1 ? init1 : tok2 ;
2014-01-15 17:32:14 +01:00
2014-01-27 06:18:42 +01:00
Token * const semicolon1 = tok2 ;
tok2 = tok2 - > next ( ) ;
2014-06-04 22:33:08 +02:00
AST_state state2 ( cpp ) ;
compileExpression ( tok2 , state2 ) ;
2014-01-27 06:18:42 +01:00
Token * const semicolon2 = tok2 ;
2015-12-26 23:51:10 +01:00
if ( ! semicolon2 )
return nullptr ; // invalid code #7235
2021-04-24 11:47:51 +02:00
if ( semicolon2 - > str ( ) = = " ; " ) {
tok2 = tok2 - > next ( ) ;
AST_state state3 ( cpp ) ;
if ( Token : : simpleMatch ( tok2 , " ( { " ) ) {
state3 . op . push ( tok2 - > next ( ) ) ;
tok2 = tok2 - > link ( ) - > next ( ) ;
}
compileExpression ( tok2 , state3 ) ;
tok2 = findAstTop ( semicolon1 - > next ( ) , semicolon2 ) ;
if ( tok2 )
semicolon2 - > astOperand1 ( tok2 ) ;
tok2 = findAstTop ( semicolon2 - > next ( ) , endPar ) ;
if ( tok2 )
semicolon2 - > astOperand2 ( tok2 ) ;
else if ( ! state3 . op . empty ( ) )
semicolon2 - > astOperand2 ( state3 . op . top ( ) ) ;
semicolon1 - > astOperand2 ( semicolon2 ) ;
} else {
2023-02-07 22:36:42 +01:00
if ( ! cpp | | state2 . op . empty ( ) | | ! Token : : simpleMatch ( state2 . op . top ( ) , " : " ) )
2021-04-24 14:07:26 +02:00
throw InternalError ( tok , " syntax error " , InternalError : : SYNTAX ) ;
semicolon1 - > astOperand2 ( state2 . op . top ( ) ) ;
2017-03-19 07:26:11 +01:00
}
2014-01-15 17:32:14 +01:00
2014-01-27 06:18:42 +01:00
if ( init ! = semicolon1 )
2019-06-16 10:09:38 +02:00
semicolon1 - > astOperand1 ( init - > astTop ( ) ) ;
2014-01-27 06:18:42 +01:00
tok - > next ( ) - > astOperand1 ( tok ) ;
tok - > next ( ) - > astOperand2 ( semicolon1 ) ;
2017-03-19 07:26:11 +01:00
createAstAtTokenInner ( endPar - > link ( ) , endPar , cpp ) ;
2015-10-18 11:42:18 +02:00
return endPar ;
2014-01-27 06:18:42 +01:00
}
2014-01-28 06:11:53 +01:00
if ( Token : : simpleMatch ( tok , " ( { " ) )
return tok ;
2019-05-12 17:24:42 +02:00
if ( Token : : Match ( tok , " %type% < " ) & & tok - > linkAt ( 1 ) & & ! Token : : Match ( tok - > linkAt ( 1 ) , " > [({] " ) )
2014-02-17 17:37:39 +01:00
return tok - > linkAt ( 1 ) ;
2022-03-27 07:59:19 +02:00
if ( cpp & & ! tok - > isKeyword ( ) & & Token : : Match ( tok , " %type% ::|<|%name% " ) ) {
2021-05-03 20:22:08 +02:00
Token * tok2 = tok ;
while ( true ) {
if ( Token : : Match ( tok2 , " %name%|> :: %name% " ) )
tok2 = tok2 - > tokAt ( 2 ) ;
else if ( Token : : Match ( tok2 , " %name% < " ) & & tok2 - > linkAt ( 1 ) )
tok2 = tok2 - > linkAt ( 1 ) ;
else
break ;
}
if ( Token : : Match ( tok2 , " %name%|> %name% { " ) & & tok2 - > next ( ) - > varId ( ) & & iscpp11init ( tok2 - > tokAt ( 2 ) ) ) {
Token * const tok1 = tok = tok2 - > next ( ) ;
AST_state state ( cpp ) ;
compileExpression ( tok , state ) ;
createAstAtTokenInner ( tok1 - > next ( ) , tok1 - > linkAt ( 1 ) , cpp ) ;
return tok ;
}
}
2022-03-27 07:59:19 +02:00
if ( Token : : Match ( tok , " %type% %name%|*|&|:: " ) & & ! Token : : Match ( tok , " return|new " ) ) {
2020-10-04 11:27:31 +02:00
int typecount = 0 ;
2019-03-09 19:09:15 +01:00
Token * typetok = tok ;
2020-10-04 11:27:31 +02:00
while ( Token : : Match ( typetok , " %type%|::|*|& " ) ) {
if ( typetok - > isName ( ) & & ! Token : : simpleMatch ( typetok - > previous ( ) , " :: " ) )
typecount + + ;
2019-03-09 19:09:15 +01:00
typetok = typetok - > next ( ) ;
2020-10-04 11:27:31 +02:00
}
2020-11-01 11:41:41 +01:00
if ( Token : : Match ( typetok , " %var% = " ) & & typetok - > varId ( ) )
tok = typetok ;
2020-10-04 11:27:31 +02:00
// Do not create AST for function declaration
if ( typetok & &
typecount > = 2 & &
! Token : : Match ( tok , " return|throw " ) & &
2022-03-30 19:22:01 +02:00
Token : : Match ( typetok - > previous ( ) , " %name% ( !!* " ) & &
2020-10-04 11:27:31 +02:00
typetok - > previous ( ) - > varId ( ) = = 0 & &
! typetok - > previous ( ) - > isKeyword ( ) & &
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
( Token : : Match ( typetok - > link ( ) , " ) const|;|{ " ) | | Token : : Match ( typetok - > link ( ) , " ) const| = delete ; " ) ) )
2020-10-04 11:27:31 +02:00
return typetok ;
2019-03-09 19:09:15 +01:00
}
2020-05-22 09:35:55 +02:00
if ( Token : : Match ( tok , " return|case " ) | |
( cpp & & tok - > str ( ) = = " throw " ) | |
! tok - > previous ( ) | |
Token : : Match ( tok , " %name% %op%|(|[|.|::|<|?|; " ) | |
2021-04-25 10:38:33 +02:00
( cpp & & Token : : Match ( tok , " %name% { " ) & & iscpp11init ( tok - > next ( ) ) ) | |
2020-05-22 09:35:55 +02:00
Token : : Match ( tok - > previous ( ) , " [;{}] %cop%|++|--|( !!{ " ) | |
2022-09-27 18:12:58 +02:00
Token : : Match ( tok - > previous ( ) , " [;{}] %num%|%str%|%char% " ) | |
Token : : Match ( tok - > previous ( ) , " [;{}] delete new " ) ) {
2016-09-10 14:54:43 +02:00
if ( cpp & & ( Token : : Match ( tok - > tokAt ( - 2 ) , " [;{}] new|delete %name% " ) | | Token : : Match ( tok - > tokAt ( - 3 ) , " [;{}] :: new|delete %name% " ) ) )
2015-10-20 23:55:29 +02:00
tok = tok - > previous ( ) ;
2014-01-27 06:18:42 +01:00
Token * const tok1 = tok ;
2014-06-04 22:33:08 +02:00
AST_state state ( cpp ) ;
2019-11-01 09:05:45 +01:00
if ( Token : : Match ( tok , " %name% ( " ) )
state . functionCallEndPar = tok - > linkAt ( 1 ) ;
2014-06-04 22:33:08 +02:00
compileExpression ( tok , state ) ;
2023-02-08 21:07:16 +01:00
Token * const endToken = tok ;
2015-10-18 11:42:18 +02:00
if ( endToken = = tok1 | | ! endToken )
2014-01-28 06:11:53 +01:00
return tok1 ;
2014-01-27 06:18:42 +01:00
2017-03-19 07:26:11 +01:00
createAstAtTokenInner ( tok1 - > next ( ) , endToken , cpp ) ;
2014-01-27 06:18:42 +01:00
2017-07-31 17:58:07 +02:00
return endToken - > previous ( ) ;
2014-01-27 06:18:42 +01:00
}
2019-04-15 06:37:27 +02:00
if ( cpp & & tok - > str ( ) = = " { " & & iscpp11init ( tok ) ) {
2020-04-03 10:04:10 +02:00
Token * const tok1 = tok ;
2019-04-15 06:37:27 +02:00
AST_state state ( cpp ) ;
compileExpression ( tok , state ) ;
2023-05-02 06:55:31 +02:00
Token * const endToken = tok ;
2020-04-03 10:04:10 +02:00
if ( endToken = = tok1 | | ! endToken )
return tok1 ;
createAstAtTokenInner ( tok1 - > next ( ) , endToken , cpp ) ;
return endToken - > previous ( ) ;
2019-04-15 06:37:27 +02:00
}
2014-01-27 06:18:42 +01:00
return tok ;
}
2021-01-09 20:32:38 +01:00
void TokenList : : createAst ( ) const
2014-01-27 06:18:42 +01:00
{
2018-06-16 16:22:35 +02:00
for ( Token * tok = mTokensFrontBack . front ; tok ; tok = tok ? tok - > next ( ) : nullptr ) {
2014-06-04 22:33:08 +02:00
tok = createAstAtToken ( tok , isCPP ( ) ) ;
2012-12-15 20:21:09 +01:00
}
2015-12-12 15:39:38 +01:00
}
2021-06-24 08:25:13 +02:00
struct OnException {
std : : function < void ( ) > f ;
~ OnException ( ) {
# ifndef _MSC_VER
if ( std : : uncaught_exception ( ) )
f ( ) ;
# endif
}
} ;
2017-01-07 14:13:22 +01:00
void TokenList : : validateAst ( ) const
2015-12-12 15:39:38 +01:00
{
2021-06-24 08:25:13 +02:00
OnException oe { [ & ] {
2023-03-03 18:31:38 +01:00
if ( mSettings & & mSettings - > debugnormal )
2021-06-24 17:10:06 +02:00
mTokensFrontBack . front - > printOut ( ) ;
} } ;
2016-02-02 08:55:26 +01:00
// Check for some known issues in AST to avoid crash/hang later on
2021-08-07 20:51:18 +02:00
std : : set < const Token * > safeAstTokens ; // list of "safe" AST tokens without endless recursion
2018-06-16 16:22:35 +02:00
for ( const Token * tok = mTokensFrontBack . front ; tok ; tok = tok - > next ( ) ) {
2015-12-12 15:39:38 +01:00
// Syntax error if binary operator only has 1 operand
if ( ( tok - > isAssignmentOp ( ) | | tok - > isComparisonOp ( ) | | Token : : Match ( tok , " [|^/%] " ) ) & & tok - > astOperand1 ( ) & & ! tok - > astOperand2 ( ) )
2017-09-05 16:56:13 +02:00
throw InternalError ( tok , " Syntax Error: AST broken, binary operator has only one operand. " , InternalError : : AST ) ;
2015-12-12 15:39:38 +01:00
// Syntax error if we encounter "?" with operand2 that is not ":"
2020-03-07 21:46:38 +01:00
if ( tok - > str ( ) = = " ? " ) {
if ( ! tok - > astOperand1 ( ) | | ! tok - > astOperand2 ( ) )
throw InternalError ( tok , " AST broken, ternary operator missing operand(s) " , InternalError::AST) ;
2023-06-20 18:43:21 +02:00
if ( tok - > astOperand2 ( ) - > str ( ) ! = " : " )
2020-03-07 21:46:38 +01:00
throw InternalError ( tok , " Syntax Error: AST broken, ternary operator lacks ':'. " , InternalError : : AST ) ;
}
2015-12-12 15:39:38 +01:00
2016-02-02 08:55:26 +01:00
// Check for endless recursion
2018-05-09 12:36:58 +02:00
const Token * parent = tok - > astParent ( ) ;
2016-02-02 08:55:26 +01:00
if ( parent ) {
2021-08-07 20:51:18 +02:00
std : : set < const Token * > astTokens ; // list of ancestors
2016-02-02 08:55:26 +01:00
astTokens . insert ( tok ) ;
do {
if ( safeAstTokens . find ( parent ) ! = safeAstTokens . end ( ) )
break ;
if ( astTokens . find ( parent ) ! = astTokens . end ( ) )
2017-09-05 16:56:13 +02:00
throw InternalError ( tok , " AST broken: endless recursion from ' " + tok - > str ( ) + " ' " , InternalError : : AST ) ;
2016-02-02 08:55:26 +01:00
astTokens . insert ( parent ) ;
} while ( ( parent = parent - > astParent ( ) ) ! = nullptr ) ;
2022-12-30 15:13:47 +01:00
safeAstTokens . insert ( astTokens . cbegin ( ) , astTokens . cend ( ) ) ;
2018-05-09 12:36:58 +02:00
} else if ( tok - > str ( ) = = " ; " ) {
safeAstTokens . clear ( ) ;
} else {
2016-02-02 08:55:26 +01:00
safeAstTokens . insert ( tok ) ;
2018-05-09 12:36:58 +02:00
}
2018-09-08 21:10:34 +02:00
2020-05-23 21:11:08 +02:00
// Don't check templates
if ( tok - > str ( ) = = " < " & & tok - > link ( ) ) {
tok = tok - > link ( ) ;
continue ;
}
2022-09-29 21:56:26 +02:00
if ( tok - > isCast ( ) & & tok - > astOperand1 ( ) & & tok - > link ( ) ) { // skip casts (not part of the AST)
tok = tok - > link ( ) ;
continue ;
}
2020-05-23 21:11:08 +02:00
2023-07-27 07:27:04 +02:00
if ( findLambdaEndToken ( tok ) ) { // skip lambda captures
2023-06-10 07:42:10 +02:00
tok = tok - > link ( ) ;
continue ;
}
2018-09-08 21:10:34 +02:00
// Check binary operators
if ( Token : : Match ( tok , " %or%|%oror%|%assign%|%comp% " ) ) {
// Skip pure virtual functions
if ( Token : : simpleMatch ( tok - > previous ( ) , " ) = 0 " ) )
continue ;
2018-10-13 18:38:44 +02:00
// Skip operator definitions
if ( Token : : simpleMatch ( tok - > previous ( ) , " operator " ) )
continue ;
2018-09-08 21:10:34 +02:00
// Skip incomplete code
if ( ! tok - > astOperand1 ( ) & & ! tok - > astOperand2 ( ) & & ! tok - > astParent ( ) )
continue ;
// Skip lambda assignment and/or initializer
2018-10-13 18:38:44 +02:00
if ( Token : : Match ( tok , " = {|^|[ " ) )
continue ;
2018-10-22 21:03:30 +02:00
// FIXME: Workaround broken AST assignment in type aliases
if ( Token : : Match ( tok - > previous ( ) , " %name% = %name% " ) )
continue ;
2018-09-08 21:10:34 +02:00
if ( ! tok - > astOperand1 ( ) | | ! tok - > astOperand2 ( ) )
2018-09-10 08:55:46 +02:00
throw InternalError ( tok , " Syntax Error: AST broken, binary operator ' " + tok - > str ( ) + " ' doesn't have two operands. " , InternalError : : AST ) ;
2018-09-08 21:10:34 +02:00
}
2019-12-01 14:53:03 +01:00
2021-08-29 20:45:31 +02:00
// Check control blocks and asserts
if ( Token : : Match ( tok - > previous ( ) , " if|while|for|switch|assert|ASSERT ( " ) ) {
2019-12-01 14:53:03 +01:00
if ( ! tok - > astOperand1 ( ) | | ! tok - > astOperand2 ( ) )
throw InternalError ( tok ,
" Syntax Error: AST broken, ' " + tok - > previous ( ) - > str ( ) +
2019-12-02 22:04:22 +01:00
" ' doesn't have two operands. " ,
2019-12-01 14:53:03 +01:00
InternalError : : AST ) ;
}
2022-01-16 12:35:51 +01:00
// Check member access
if ( Token : : Match ( tok , " %var% . " ) ) {
if ( ! tok - > astParent ( ) ) {
throw InternalError (
tok , " Syntax Error: AST broken, ' " + tok - > str ( ) + " ' doesn't have a parent. " , InternalError : : AST ) ;
}
if ( ! tok - > next ( ) - > astOperand1 ( ) | | ! tok - > next ( ) - > astOperand2 ( ) ) {
const std : : string & op =
tok - > next ( ) - > originalName ( ) . empty ( ) ? tok - > next ( ) - > str ( ) : tok - > next ( ) - > originalName ( ) ;
throw InternalError (
tok , " Syntax Error: AST broken, ' " + op + " ' doesn't have two operands. " , InternalError : : AST ) ;
}
}
2015-12-12 15:39:38 +01:00
}
}
2018-11-18 16:08:08 +01:00
std : : string TokenList : : getOrigFile ( const Token * tok ) const
{
return mOrigFiles . at ( tok - > fileIndex ( ) ) ;
}
2012-05-05 18:33:26 +02:00
const std : : string & TokenList : : file ( const Token * tok ) const
{
2018-06-16 16:23:55 +02:00
return mFiles . at ( tok - > fileIndex ( ) ) ;
2012-05-05 18:33:26 +02:00
}
std : : string TokenList : : fileLine ( const Token * tok ) const
{
2020-05-23 07:16:49 +02:00
return ErrorMessage : : FileLocation ( tok , this ) . stringify ( ) ;
2012-05-05 18:33:26 +02:00
}
2015-12-27 17:38:15 +01:00
bool TokenList : : validateToken ( const Token * tok ) const
{
if ( ! tok )
return true ;
2018-06-16 16:22:35 +02:00
for ( const Token * t = mTokensFrontBack . front ; t ; t = t - > next ( ) ) {
2015-12-27 17:38:15 +01:00
if ( tok = = t )
return true ;
}
return false ;
}
2017-10-03 22:10:13 +02:00
2019-02-15 13:29:52 +01:00
void TokenList : : simplifyPlatformTypes ( )
{
2023-03-03 18:31:38 +01:00
if ( ! mSettings )
return ;
2019-02-15 13:29:52 +01:00
const bool isCPP11 = mSettings - > standards . cpp > = Standards : : CPP11 ;
enum { isLongLong , isLong , isInt } type ;
/** @todo This assumes a flat address space. Not true for segmented address space (FAR *). */
2023-03-03 18:36:27 +01:00
if ( mSettings - > platform . sizeof_size_t = = mSettings - > platform . sizeof_long )
2019-02-15 13:29:52 +01:00
type = isLong ;
2023-03-03 18:36:27 +01:00
else if ( mSettings - > platform . sizeof_size_t = = mSettings - > platform . sizeof_long_long )
2019-02-15 13:29:52 +01:00
type = isLongLong ;
2023-03-03 18:36:27 +01:00
else if ( mSettings - > platform . sizeof_size_t = = mSettings - > platform . sizeof_int )
2019-02-15 13:29:52 +01:00
type = isInt ;
else
return ;
for ( Token * tok = front ( ) ; tok ; tok = tok - > next ( ) ) {
// pre-check to reduce unneeded match calls
if ( ! Token : : Match ( tok , " std| ::| %type% " ) )
continue ;
bool isUnsigned ;
if ( Token : : Match ( tok , " std| ::| size_t|uintptr_t|uintmax_t " ) ) {
if ( isCPP11 & & tok - > strAt ( - 1 ) = = " using " & & tok - > strAt ( 1 ) = = " = " )
continue ;
isUnsigned = true ;
} else if ( Token : : Match ( tok , " std| ::| ssize_t|ptrdiff_t|intptr_t|intmax_t " ) ) {
if ( isCPP11 & & tok - > strAt ( - 1 ) = = " using " & & tok - > strAt ( 1 ) = = " = " )
continue ;
isUnsigned = false ;
} else
continue ;
bool inStd = false ;
if ( tok - > str ( ) = = " :: " ) {
tok - > deleteThis ( ) ;
} else if ( tok - > str ( ) = = " std " ) {
if ( tok - > next ( ) - > str ( ) ! = " :: " )
continue ;
inStd = true ;
tok - > deleteNext ( ) ;
tok - > deleteThis ( ) ;
}
if ( inStd )
tok - > originalName ( " std:: " + tok - > str ( ) ) ;
else
tok - > originalName ( tok - > str ( ) ) ;
if ( isUnsigned )
tok - > isUnsigned ( true ) ;
switch ( type ) {
case isLongLong :
tok - > isLong ( true ) ;
tok - > str ( " long " ) ;
break ;
case isLong :
tok - > str ( " long " ) ;
break ;
case isInt :
tok - > str ( " int " ) ;
break ;
}
}
2023-03-03 18:36:27 +01:00
const std : : string platform_type ( mSettings - > platform . toString ( ) ) ;
2019-02-15 13:29:52 +01:00
for ( Token * tok = front ( ) ; tok ; tok = tok - > next ( ) ) {
if ( tok - > tokType ( ) ! = Token : : eType & & tok - > tokType ( ) ! = Token : : eName )
continue ;
const Library : : PlatformType * const platformtype = mSettings - > library . platform_type ( tok - > str ( ) , platform_type ) ;
if ( platformtype ) {
// check for namespace
if ( tok - > strAt ( - 1 ) = = " :: " ) {
const Token * tok1 = tok - > tokAt ( - 2 ) ;
// skip when non-global namespace defined
if ( tok1 & & tok1 - > tokType ( ) = = Token : : eName )
continue ;
tok = tok - > previous ( ) ;
tok - > deleteThis ( ) ;
}
Token * typeToken ;
2019-11-20 15:37:09 +01:00
if ( platformtype - > mConstPtr ) {
2019-02-15 13:29:52 +01:00
tok - > str ( " const " ) ;
tok - > insertToken ( " * " ) ;
tok - > insertToken ( platformtype - > mType ) ;
typeToken = tok ;
2019-11-20 15:37:09 +01:00
} else if ( platformtype - > mPointer ) {
2019-02-15 13:29:52 +01:00
tok - > str ( platformtype - > mType ) ;
typeToken = tok ;
tok - > insertToken ( " * " ) ;
2019-11-20 15:37:09 +01:00
} else if ( platformtype - > mPtrPtr ) {
2019-02-15 13:29:52 +01:00
tok - > str ( platformtype - > mType ) ;
typeToken = tok ;
tok - > insertToken ( " * " ) ;
tok - > insertToken ( " * " ) ;
} else {
tok - > originalName ( tok - > str ( ) ) ;
tok - > str ( platformtype - > mType ) ;
typeToken = tok ;
}
2019-11-20 15:37:09 +01:00
if ( platformtype - > mSigned )
2019-02-15 13:29:52 +01:00
typeToken - > isSigned ( true ) ;
2019-11-20 15:37:09 +01:00
if ( platformtype - > mUnsigned )
2019-02-15 13:29:52 +01:00
typeToken - > isUnsigned ( true ) ;
2019-11-20 15:37:09 +01:00
if ( platformtype - > mLong )
2019-02-15 13:29:52 +01:00
typeToken - > isLong ( true ) ;
}
}
}
2017-10-03 22:10:13 +02:00
void TokenList : : simplifyStdType ( )
{
2023-01-18 20:37:00 +01:00
auto isVarDeclC = [ ] ( const Token * tok ) - > bool {
if ( ! Token : : simpleMatch ( tok , " } " ) )
return false ;
tok = tok - > link ( ) - > previous ( ) ;
while ( Token : : Match ( tok , " %name% " ) ) {
if ( Token : : Match ( tok , " struct|union|enum " ) )
return true ;
tok = tok - > previous ( ) ;
}
return false ;
} ;
2017-10-03 22:10:13 +02:00
for ( Token * tok = front ( ) ; tok ; tok = tok - > next ( ) ) {
2021-07-07 13:34:55 +02:00
2023-01-18 20:37:00 +01:00
if ( isC ( ) & & Token : : Match ( tok , " const|extern *|&|%name% " ) & & ( ! tok - > previous ( ) | | Token : : Match ( tok - > previous ( ) , " [;{}] " ) ) ) {
2021-07-07 13:34:55 +02:00
if ( Token : : Match ( tok - > next ( ) , " %name% !!; " ) )
continue ;
2023-01-18 20:37:00 +01:00
if ( isVarDeclC ( tok - > previous ( ) ) )
continue ;
2021-07-07 13:34:55 +02:00
tok - > insertToken ( " int " ) ;
tok - > next ( ) - > isImplicitInt ( true ) ;
continue ;
}
2018-06-16 16:10:28 +02:00
if ( Token : : Match ( tok , " char|short|int|long|unsigned|signed|double|float " ) | | ( mSettings - > standards . c > = Standards : : C99 & & Token : : Match ( tok , " complex|_Complex " ) ) ) {
2017-10-03 22:10:13 +02:00
bool isFloat = false ;
bool isSigned = false ;
bool isUnsigned = false ;
bool isComplex = false ;
2019-07-17 10:14:00 +02:00
int countLong = 0 ;
2017-10-03 22:10:13 +02:00
Token * typeSpec = nullptr ;
Token * tok2 = tok ;
for ( ; tok2 - > next ( ) ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) = = " long " ) {
countLong + + ;
if ( ! isFloat )
typeSpec = tok2 ;
} else if ( tok2 - > str ( ) = = " short " ) {
typeSpec = tok2 ;
} else if ( tok2 - > str ( ) = = " unsigned " )
isUnsigned = true ;
else if ( tok2 - > str ( ) = = " signed " )
isSigned = true ;
else if ( Token : : Match ( tok2 , " float|double " ) ) {
isFloat = true ;
typeSpec = tok2 ;
2018-06-16 16:10:28 +02:00
} else if ( mSettings - > standards . c > = Standards : : C99 & & Token : : Match ( tok2 , " complex|_Complex " ) )
2017-10-03 22:10:13 +02:00
isComplex = ! isFloat | | tok2 - > str ( ) = = " _Complex " | | Token : : Match ( tok2 - > next ( ) , " *|&|%name% " ) ; // Ensure that "complex" is not the variables name
else if ( Token : : Match ( tok2 , " char|int " ) ) {
if ( ! typeSpec )
typeSpec = tok2 ;
} else
break ;
}
if ( ! typeSpec ) { // unsigned i; or similar declaration
if ( ! isComplex ) { // Ensure that "complex" is not the variables name
tok - > str ( " int " ) ;
tok - > isSigned ( isSigned ) ;
tok - > isUnsigned ( isUnsigned ) ;
2021-07-07 13:34:55 +02:00
tok - > isImplicitInt ( true ) ;
2017-10-03 22:10:13 +02:00
}
} else {
typeSpec - > isLong ( typeSpec - > isLong ( ) | | ( isFloat & & countLong = = 1 ) | | countLong > 1 ) ;
typeSpec - > isComplex ( typeSpec - > isComplex ( ) | | ( isFloat & & isComplex ) ) ;
typeSpec - > isSigned ( typeSpec - > isSigned ( ) | | isSigned ) ;
typeSpec - > isUnsigned ( typeSpec - > isUnsigned ( ) | | isUnsigned ) ;
// Remove specifiers
const Token * tok3 = tok - > previous ( ) ;
tok2 = tok2 - > previous ( ) ;
while ( tok3 ! = tok2 ) {
if ( tok2 ! = typeSpec & &
( isComplex | | ! Token : : Match ( tok2 , " complex|_Complex " ) ) ) // Ensure that "complex" is not the variables name
tok2 - > deleteThis ( ) ;
tok2 = tok2 - > previous ( ) ;
}
}
}
}
}
2020-02-22 11:57:09 +01:00
bool TokenList : : isKeyword ( const std : : string & str ) const
{
2023-02-24 21:43:27 +01:00
if ( mIsCpp ) {
// TODO: integrate into keywords?
// types and literals are not handled as keywords
static const std : : unordered_set < std : : string > cpp_types = { " bool " , " false " , " true " } ;
if ( cpp_types . find ( str ) ! = cpp_types . end ( ) )
return false ;
// TODO: properly apply configured standard
if ( ! mSettings | | mSettings - > standards . cpp > = Standards : : CPP20 ) {
static const auto & cpp20_keywords = Keywords : : getAll ( Standards : : cppstd_t : : CPP20 ) ;
return cpp20_keywords . find ( str ) ! = cpp20_keywords . end ( ) ;
}
static const auto & cpp_keywords = Keywords : : getAll ( Standards : : cppstd_t : : CPP11 ) ;
return cpp_keywords . find ( str ) ! = cpp_keywords . end ( ) ;
}
// TODO: integrate into Keywords?
// types are not handled as keywords
static const std : : unordered_set < std : : string > c_types = { " char " , " double " , " float " , " int " , " long " , " short " } ;
if ( c_types . find ( str ) ! = c_types . end ( ) )
return false ;
// TODO: use configured standard
static const auto & c_keywords = Keywords : : getAll ( Standards : : cstd_t : : C99 ) ;
return c_keywords . find ( str ) ! = c_keywords . end ( ) ;
2020-02-22 11:57:09 +01:00
}