2016-01-14 01:58:09 +00:00
/*
2016-11-18 23:13:20 +00:00
This file is part of solidity .
2016-01-14 01:58:09 +00:00
2016-11-18 23:13:20 +00:00
solidity is free software : you can redistribute it and / or modify
2016-01-14 01:58:09 +00:00
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 .
2016-11-18 23:13:20 +00:00
solidity is distributed in the hope that it will be useful ,
2016-01-14 01:58:09 +00:00
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
2016-11-18 23:13:20 +00:00
along with solidity . If not , see < http : //www.gnu.org/licenses/>.
2016-01-14 01:58:09 +00:00
*/
2020-07-17 14:54:12 +00:00
// SPDX-License-Identifier: GPL-3.0
2016-01-14 01:58:09 +00:00
2016-08-19 17:57:21 +00:00
# include <libsolidity/analysis/SyntaxChecker.h>
2018-12-17 11:30:08 +00:00
2016-01-14 01:58:09 +00:00
# include <libsolidity/ast/AST.h>
2017-08-08 13:09:57 +00:00
# include <libsolidity/ast/ExperimentalFeatures.h>
2016-08-19 17:57:21 +00:00
# include <libsolidity/interface/Version.h>
2016-01-14 01:58:09 +00:00
2019-05-27 12:01:53 +00:00
# include <libyul/optimiser/Semantics.h>
# include <libyul/AsmData.h>
2018-12-17 11:30:08 +00:00
# include <liblangutil/ErrorReporter.h>
2019-04-17 11:02:30 +00:00
# include <liblangutil/SemVerHandler.h>
2018-12-17 11:30:08 +00:00
2020-07-02 16:39:04 +00:00
# include <libsolutil/UTF8.h>
2017-10-25 08:12:07 +00:00
# include <boost/algorithm/string.hpp>
2018-12-17 11:30:08 +00:00
# include <memory>
2017-10-25 08:12:07 +00:00
# include <string>
2016-01-14 01:58:09 +00:00
using namespace std ;
2019-12-11 16:31:36 +00:00
using namespace solidity ;
using namespace solidity : : langutil ;
using namespace solidity : : frontend ;
2020-07-02 16:39:04 +00:00
using namespace solidity : : util ;
2016-01-14 01:58:09 +00:00
2017-01-27 17:27:59 +00:00
bool SyntaxChecker : : checkSyntax ( ASTNode const & _astRoot )
2016-01-14 01:58:09 +00:00
{
2017-01-27 17:27:59 +00:00
_astRoot . accept ( * this ) ;
2017-05-11 13:26:35 +00:00
return Error : : containsOnlyWarnings ( m_errorReporter . errors ( ) ) ;
2016-01-14 01:58:09 +00:00
}
2017-07-08 23:10:22 +00:00
bool SyntaxChecker : : visit ( SourceUnit const & _sourceUnit )
2016-08-19 17:57:21 +00:00
{
m_versionPragmaFound = false ;
2017-07-08 23:10:22 +00:00
m_sourceUnit = & _sourceUnit ;
2016-08-19 17:57:21 +00:00
return true ;
}
void SyntaxChecker : : endVisit ( SourceUnit const & _sourceUnit )
{
if ( ! m_versionPragmaFound )
{
2016-10-05 09:58:25 +00:00
string errorString ( " Source file does not specify required compiler version! " ) ;
SemVerVersion recommendedVersion { string ( VersionString ) } ;
if ( ! recommendedVersion . isPrerelease ( ) )
errorString + =
2018-10-08 20:58:34 +00:00
" Consider adding \" pragma solidity ^ " +
2016-10-05 09:58:25 +00:00
to_string ( recommendedVersion . major ( ) ) +
string ( " . " ) +
to_string ( recommendedVersion . minor ( ) ) +
string ( " . " ) +
2017-11-14 12:45:51 +00:00
to_string ( recommendedVersion . patch ( ) ) +
2016-10-05 09:58:25 +00:00
string ( " ; \" " ) ;
2020-02-07 01:36:51 +00:00
// when reporting the warning, print the source name only
2020-05-05 22:38:28 +00:00
m_errorReporter . warning ( 3420 _error , { - 1 , - 1 , _sourceUnit . location ( ) . source } , errorString ) ;
2016-08-19 17:57:21 +00:00
}
2017-07-08 23:10:22 +00:00
m_sourceUnit = nullptr ;
2016-08-19 17:57:21 +00:00
}
bool SyntaxChecker : : visit ( PragmaDirective const & _pragma )
{
solAssert ( ! _pragma . tokens ( ) . empty ( ) , " " ) ;
solAssert ( _pragma . tokens ( ) . size ( ) = = _pragma . literals ( ) . size ( ) , " " ) ;
2017-07-08 23:10:22 +00:00
if ( _pragma . tokens ( ) [ 0 ] ! = Token : : Identifier )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 5226 _error , _pragma . location ( ) , " Invalid pragma \" " + _pragma . literals ( ) [ 0 ] + " \" " ) ;
2017-07-08 23:10:22 +00:00
else if ( _pragma . literals ( ) [ 0 ] = = " experimental " )
{
solAssert ( m_sourceUnit , " " ) ;
vector < string > literals ( _pragma . literals ( ) . begin ( ) + 1 , _pragma . literals ( ) . end ( ) ) ;
2018-10-09 03:29:37 +00:00
if ( literals . empty ( ) )
2017-07-08 23:10:22 +00:00
m_errorReporter . syntaxError (
2020-05-05 22:38:28 +00:00
9679 _error ,
2017-07-08 23:10:22 +00:00
_pragma . location ( ) ,
2017-08-04 22:28:28 +00:00
" Experimental feature name is missing. "
) ;
else if ( literals . size ( ) > 1 )
m_errorReporter . syntaxError (
2020-05-05 22:38:28 +00:00
6022 _error ,
2017-08-04 22:28:28 +00:00
_pragma . location ( ) ,
" Stray arguments. "
2017-07-08 23:10:22 +00:00
) ;
else
2017-08-02 19:05:35 +00:00
{
2017-08-04 22:28:28 +00:00
string const literal = literals [ 0 ] ;
if ( literal . empty ( ) )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 3250 _error , _pragma . location ( ) , " Empty experimental feature name is invalid. " ) ;
2017-08-08 13:09:57 +00:00
else if ( ! ExperimentalFeatureNames . count ( literal ) )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 8491 _error , _pragma . location ( ) , " Unsupported experimental feature name. " ) ;
2017-08-08 13:09:57 +00:00
else if ( m_sourceUnit - > annotation ( ) . experimentalFeatures . count ( ExperimentalFeatureNames . at ( literal ) ) )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 1231 _error , _pragma . location ( ) , " Duplicate experimental feature name. " ) ;
2017-08-04 22:28:28 +00:00
else
2017-07-08 23:10:22 +00:00
{
2018-02-21 15:33:59 +00:00
auto feature = ExperimentalFeatureNames . at ( literal ) ;
m_sourceUnit - > annotation ( ) . experimentalFeatures . insert ( feature ) ;
2019-11-20 11:29:08 +00:00
if ( ! ExperimentalFeatureWithoutWarning . count ( feature ) )
2020-05-05 22:38:28 +00:00
m_errorReporter . warning ( 2264 _error , _pragma . location ( ) , " Experimental features are turned on. Do not use experimental features on live deployments. " ) ;
2017-07-08 23:10:22 +00:00
}
2017-08-02 19:05:35 +00:00
}
2017-07-08 23:10:22 +00:00
}
else if ( _pragma . literals ( ) [ 0 ] = = " solidity " )
2016-08-19 17:57:21 +00:00
{
2018-10-22 14:48:21 +00:00
vector < Token > tokens ( _pragma . tokens ( ) . begin ( ) + 1 , _pragma . tokens ( ) . end ( ) ) ;
2016-08-19 17:57:21 +00:00
vector < string > literals ( _pragma . literals ( ) . begin ( ) + 1 , _pragma . literals ( ) . end ( ) ) ;
SemVerMatchExpressionParser parser ( tokens , literals ) ;
auto matchExpression = parser . parse ( ) ;
2018-12-12 15:45:17 +00:00
static SemVerVersion const currentVersion { string ( VersionString ) } ;
2016-08-19 17:57:21 +00:00
if ( ! matchExpression . matches ( currentVersion ) )
2017-05-11 13:26:35 +00:00
m_errorReporter . syntaxError (
2020-05-05 22:38:28 +00:00
3997 _error ,
2016-08-19 17:57:21 +00:00
_pragma . location ( ) ,
" Source file requires different compiler version (current compiler is " +
2020-04-18 01:00:22 +00:00
string ( VersionString ) + " ) - note that nightly builds are considered to be "
2016-08-23 15:03:23 +00:00
" strictly less than the released version "
2016-08-19 17:57:21 +00:00
) ;
m_versionPragmaFound = true ;
}
2017-07-08 23:10:22 +00:00
else
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 4936 _error , _pragma . location ( ) , " Unknown pragma \" " + _pragma . literals ( ) [ 0 ] + " \" " ) ;
2016-08-19 17:57:21 +00:00
return true ;
}
2016-08-06 13:08:06 +00:00
bool SyntaxChecker : : visit ( ModifierDefinition const & )
{
m_placeholderFound = false ;
return true ;
}
void SyntaxChecker : : endVisit ( ModifierDefinition const & _modifier )
{
2020-04-15 10:42:15 +00:00
if ( _modifier . isImplemented ( ) & & ! m_placeholderFound )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 2883 _error , _modifier . body ( ) . location ( ) , " Modifier body does not contain '_'. " ) ;
2016-08-06 13:08:06 +00:00
m_placeholderFound = false ;
}
2018-09-04 10:14:04 +00:00
void SyntaxChecker : : checkSingleStatementVariableDeclaration ( ASTNode const & _statement )
2018-09-03 16:17:59 +00:00
{
2018-09-04 10:14:04 +00:00
auto varDecl = dynamic_cast < VariableDeclarationStatement const * > ( & _statement ) ;
2018-09-03 16:17:59 +00:00
if ( varDecl )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 9079 _error , _statement . location ( ) , " Variable declarations can only be used inside blocks. " ) ;
2018-09-03 16:17:59 +00:00
}
bool SyntaxChecker : : visit ( IfStatement const & _ifStatement )
{
2018-09-04 10:14:04 +00:00
checkSingleStatementVariableDeclaration ( _ifStatement . trueStatement ( ) ) ;
2018-09-03 16:17:59 +00:00
if ( Statement const * _statement = _ifStatement . falseStatement ( ) )
2018-09-04 10:14:04 +00:00
checkSingleStatementVariableDeclaration ( * _statement ) ;
2018-09-03 16:17:59 +00:00
return true ;
}
bool SyntaxChecker : : visit ( WhileStatement const & _whileStatement )
2016-01-14 01:58:09 +00:00
{
2016-01-19 02:16:13 +00:00
m_inLoopDepth + + ;
2018-09-04 10:14:04 +00:00
checkSingleStatementVariableDeclaration ( _whileStatement . body ( ) ) ;
2016-01-14 01:58:09 +00:00
return true ;
}
2017-08-15 12:22:50 +00:00
void SyntaxChecker : : endVisit ( WhileStatement const & )
2016-01-14 01:58:09 +00:00
{
2016-01-19 02:16:13 +00:00
m_inLoopDepth - - ;
2016-01-14 01:58:09 +00:00
}
2018-09-03 16:17:59 +00:00
bool SyntaxChecker : : visit ( ForStatement const & _forStatement )
2016-01-14 01:58:09 +00:00
{
2016-01-19 02:16:13 +00:00
m_inLoopDepth + + ;
2018-09-04 10:14:04 +00:00
checkSingleStatementVariableDeclaration ( _forStatement . body ( ) ) ;
2016-01-14 01:58:09 +00:00
return true ;
}
2016-01-19 02:18:01 +00:00
void SyntaxChecker : : endVisit ( ForStatement const & )
2016-01-14 01:58:09 +00:00
{
2016-01-19 02:16:13 +00:00
m_inLoopDepth - - ;
2016-01-14 01:58:09 +00:00
}
bool SyntaxChecker : : visit ( Continue const & _continueStatement )
{
2016-01-19 02:16:13 +00:00
if ( m_inLoopDepth < = 0 )
2016-01-14 01:58:09 +00:00
// we're not in a for/while loop, report syntax error
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 4123 _error , _continueStatement . location ( ) , " \" continue \" has to be in a \" for \" or \" while \" loop. " ) ;
2016-01-14 01:58:09 +00:00
return true ;
}
bool SyntaxChecker : : visit ( Break const & _breakStatement )
{
2016-01-19 02:16:13 +00:00
if ( m_inLoopDepth < = 0 )
2016-01-14 01:58:09 +00:00
// we're not in a for/while loop, report syntax error
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 6102 _error , _breakStatement . location ( ) , " \" break \" has to be in a \" for \" or \" while \" loop. " ) ;
2016-01-14 01:58:09 +00:00
return true ;
}
2017-07-05 17:45:12 +00:00
bool SyntaxChecker : : visit ( Throw const & _throwStatement )
{
2018-07-11 14:06:31 +00:00
m_errorReporter . syntaxError (
2020-05-05 22:38:28 +00:00
4538 _error ,
2018-07-11 14:06:31 +00:00
_throwStatement . location ( ) ,
" \" throw \" is deprecated in favour of \" revert() \" , \" require() \" and \" assert() \" . "
) ;
2017-07-05 17:45:12 +00:00
return true ;
}
2017-10-25 08:12:07 +00:00
bool SyntaxChecker : : visit ( Literal const & _literal )
{
2020-07-02 16:39:04 +00:00
if ( ( _literal . token ( ) = = Token : : UnicodeStringLiteral ) & & ! validateUTF8 ( _literal . value ( ) ) )
m_errorReporter . syntaxError (
8452 _error ,
_literal . location ( ) ,
" Invalid UTF-8 sequence found "
) ;
2018-08-03 14:13:52 +00:00
if ( _literal . token ( ) ! = Token : : Number )
2017-10-25 08:12:07 +00:00
return true ;
2018-08-03 14:13:52 +00:00
ASTString const & value = _literal . value ( ) ;
solAssert ( ! value . empty ( ) , " " ) ;
2017-10-25 08:12:07 +00:00
2018-08-03 14:13:52 +00:00
// Generic checks no matter what base this number literal is of:
if ( value . back ( ) = = ' _ ' )
{
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 2090 _error , _literal . location ( ) , " Invalid use of underscores in number literal. No trailing underscores allowed. " ) ;
2017-10-25 08:12:07 +00:00
return true ;
2018-08-03 14:13:52 +00:00
}
2017-10-25 08:12:07 +00:00
2018-08-03 14:13:52 +00:00
if ( value . find ( " __ " ) ! = ASTString : : npos )
2017-10-25 08:12:07 +00:00
{
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 2990 _error , _literal . location ( ) , " Invalid use of underscores in number literal. Only one consecutive underscores between digits allowed. " ) ;
2018-08-03 14:13:52 +00:00
return true ;
2017-10-25 08:12:07 +00:00
}
2018-08-03 14:13:52 +00:00
if ( ! _literal . isHexNumber ( ) ) // decimal literal
2017-10-25 08:12:07 +00:00
{
2018-08-03 14:13:52 +00:00
if ( value . find ( " ._ " ) ! = ASTString : : npos )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 3891 _error , _literal . location ( ) , " Invalid use of underscores in number literal. No underscores in front of the fraction part allowed. " ) ;
2018-08-03 14:13:52 +00:00
if ( value . find ( " _. " ) ! = ASTString : : npos )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 1023 _error , _literal . location ( ) , " Invalid use of underscores in number literal. No underscores in front of the fraction part allowed. " ) ;
2018-08-03 14:13:52 +00:00
if ( value . find ( " _e " ) ! = ASTString : : npos )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 6415 _error , _literal . location ( ) , " Invalid use of underscores in number literal. No underscore at the end of the mantissa allowed. " ) ;
2018-08-03 14:13:52 +00:00
if ( value . find ( " e_ " ) ! = ASTString : : npos )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 6165 _error , _literal . location ( ) , " Invalid use of underscores in number literal. No underscore in front of exponent allowed. " ) ;
2017-10-25 08:12:07 +00:00
}
return true ;
}
2017-04-29 00:43:19 +00:00
bool SyntaxChecker : : visit ( UnaryOperation const & _operation )
{
if ( _operation . getOperator ( ) = = Token : : Add )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 9636 _error , _operation . location ( ) , " Use of unary + is disallowed. " ) ;
2018-07-03 09:10:14 +00:00
2017-04-29 00:43:19 +00:00
return true ;
}
2019-05-27 12:01:53 +00:00
bool SyntaxChecker : : visit ( InlineAssembly const & _inlineAssembly )
{
if ( ! m_useYulOptimizer )
return false ;
2019-08-13 11:34:33 +00:00
if ( yul : : MSizeFinder : : containsMSize ( _inlineAssembly . dialect ( ) , _inlineAssembly . operations ( ) ) )
2019-05-27 12:01:53 +00:00
m_errorReporter . syntaxError (
2020-05-05 22:38:28 +00:00
6553 _error ,
2019-05-27 12:01:53 +00:00
_inlineAssembly . location ( ) ,
" The msize instruction cannot be used when the Yul optimizer is activated because "
" it can change its semantics. Either disable the Yul optimizer or do not use the instruction. "
) ;
2020-05-12 15:09:25 +00:00
2019-05-27 12:01:53 +00:00
return false ;
}
2016-08-19 17:57:21 +00:00
bool SyntaxChecker : : visit ( PlaceholderStatement const & )
2016-08-06 13:08:06 +00:00
{
m_placeholderFound = true ;
return true ;
}
2018-07-10 20:43:02 +00:00
bool SyntaxChecker : : visit ( ContractDefinition const & _contract )
{
2020-05-04 16:38:00 +00:00
m_currentContractKind = _contract . contractKind ( ) ;
2018-06-27 10:29:03 +00:00
ASTString const & contractName = _contract . name ( ) ;
for ( FunctionDefinition const * function : _contract . definedFunctions ( ) )
if ( function - > name ( ) = = contractName )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError (
2020-05-07 01:52:53 +00:00
5796 _error ,
function - > location ( ) ,
2018-06-27 10:29:03 +00:00
" Functions are not allowed to have the same name as the contract. "
" If you intend this to be a constructor, use \" constructor(...) { ... } \" to define it. "
) ;
2018-07-10 20:43:02 +00:00
return true ;
}
2020-05-04 16:38:00 +00:00
void SyntaxChecker : : endVisit ( ContractDefinition const & )
{
m_currentContractKind = std : : nullopt ;
}
2017-08-15 12:22:50 +00:00
bool SyntaxChecker : : visit ( FunctionDefinition const & _function )
{
2020-05-04 16:38:00 +00:00
solAssert ( _function . isFree ( ) = = ( m_currentContractKind = = std : : nullopt ) , " " ) ;
if ( ! _function . isFree ( ) & & ! _function . isConstructor ( ) & & _function . noVisibilitySpecified ( ) )
2018-07-10 20:43:02 +00:00
{
2020-05-04 16:38:00 +00:00
string suggestedVisibility =
_function . isFallback ( ) | |
_function . isReceive ( ) | |
m_currentContractKind = = ContractKind : : Interface
? " external " : " public " ;
2018-07-10 20:43:02 +00:00
m_errorReporter . syntaxError (
2020-05-05 22:38:28 +00:00
4937 _error ,
2018-07-10 20:43:02 +00:00
_function . location ( ) ,
" No visibility specified. Did you intend to add \" " + suggestedVisibility + " \" ? "
) ;
}
2020-05-04 16:38:00 +00:00
else if ( _function . isFree ( ) )
{
if ( ! _function . noVisibilitySpecified ( ) )
m_errorReporter . syntaxError (
4126 _error ,
_function . location ( ) ,
" Free functions cannot have visibility. "
) ;
if ( ! _function . isImplemented ( ) )
m_errorReporter . typeError ( 4668 _error , _function . location ( ) , " Free functions must be implemented. " ) ;
}
2018-03-01 17:39:01 +00:00
2020-05-04 16:38:00 +00:00
if ( m_currentContractKind = = ContractKind : : Interface & & ! _function . modifiers ( ) . empty ( ) )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 5842 _error , _function . location ( ) , " Functions in interfaces cannot have modifiers. " ) ;
2020-04-02 15:00:43 +00:00
else if ( ! _function . isImplemented ( ) & & ! _function . modifiers ( ) . empty ( ) )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 2668 _error , _function . location ( ) , " Functions without implementation cannot have modifiers. " ) ;
2018-07-03 09:28:57 +00:00
2017-08-15 12:22:50 +00:00
return true ;
}
2017-06-24 17:09:19 +00:00
bool SyntaxChecker : : visit ( FunctionTypeName const & _node )
{
for ( auto const & decl : _node . parameterTypeList ( ) - > parameters ( ) )
if ( ! decl - > name ( ) . empty ( ) )
2020-05-05 22:38:28 +00:00
m_errorReporter . warning ( 6162 _error , decl - > location ( ) , " Naming function type parameters is deprecated. " ) ;
2017-06-24 17:09:19 +00:00
for ( auto const & decl : _node . returnParameterTypeList ( ) - > parameters ( ) )
if ( ! decl - > name ( ) . empty ( ) )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 7304 _error , decl - > location ( ) , " Return parameters in function types may not be named. " ) ;
2017-06-24 17:09:19 +00:00
return true ;
}
2018-01-22 21:32:47 +00:00
2018-03-27 13:38:28 +00:00
bool SyntaxChecker : : visit ( StructDefinition const & _struct )
{
if ( _struct . members ( ) . empty ( ) )
2020-05-05 22:38:28 +00:00
m_errorReporter . syntaxError ( 5306 _error , _struct . location ( ) , " Defining empty structs is disallowed. " ) ;
2018-06-06 09:15:22 +00:00
2018-03-27 13:38:28 +00:00
return true ;
}