/src/solidity/libsolidity/analysis/SyntaxChecker.cpp
Line | Count | Source |
1 | | /* |
2 | | This file is part of solidity. |
3 | | |
4 | | solidity is free software: you can redistribute it and/or modify |
5 | | it under the terms of the GNU General Public License as published by |
6 | | the Free Software Foundation, either version 3 of the License, or |
7 | | (at your option) any later version. |
8 | | |
9 | | solidity is distributed in the hope that it will be useful, |
10 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | GNU General Public License for more details. |
13 | | |
14 | | You should have received a copy of the GNU General Public License |
15 | | along with solidity. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | // SPDX-License-Identifier: GPL-3.0 |
18 | | |
19 | | #include <libsolidity/analysis/SyntaxChecker.h> |
20 | | |
21 | | #include <libsolidity/ast/AST.h> |
22 | | #include <libsolidity/ast/ExperimentalFeatures.h> |
23 | | #include <libsolidity/interface/Version.h> |
24 | | |
25 | | #include <libyul/optimiser/Semantics.h> |
26 | | #include <libyul/AST.h> |
27 | | |
28 | | #include <liblangutil/ErrorReporter.h> |
29 | | #include <liblangutil/SemVerHandler.h> |
30 | | |
31 | | #include <libsolutil/UTF8.h> |
32 | | |
33 | | #include <string> |
34 | | |
35 | | using namespace solidity; |
36 | | using namespace solidity::langutil; |
37 | | using namespace solidity::frontend; |
38 | | using namespace solidity::util; |
39 | | |
40 | | bool SyntaxChecker::checkSyntax(ASTNode const& _astRoot) |
41 | 28.2k | { |
42 | 28.2k | _astRoot.accept(*this); |
43 | 28.2k | return !Error::containsErrors(m_errorReporter.errors()); |
44 | 28.2k | } |
45 | | |
46 | | bool SyntaxChecker::visit(SourceUnit const& _sourceUnit) |
47 | 28.2k | { |
48 | 28.2k | m_versionPragmaFound = false; |
49 | 28.2k | m_sourceUnit = &_sourceUnit; |
50 | 28.2k | return true; |
51 | 28.2k | } |
52 | | |
53 | | void SyntaxChecker::endVisit(SourceUnit const& _sourceUnit) |
54 | 28.2k | { |
55 | 28.2k | if (!m_versionPragmaFound) |
56 | 26.6k | { |
57 | 26.6k | std::string errorString("Source file does not specify required compiler version!"); |
58 | 26.6k | SemVerVersion recommendedVersion{std::string(VersionString)}; |
59 | 26.6k | if (!recommendedVersion.isPrerelease()) |
60 | 0 | errorString += |
61 | 0 | " Consider adding \"pragma solidity ^" + |
62 | 0 | std::to_string(recommendedVersion.major()) + |
63 | 0 | std::string(".") + |
64 | 0 | std::to_string(recommendedVersion.minor()) + |
65 | 0 | std::string(".") + |
66 | 0 | std::to_string(recommendedVersion.patch()) + |
67 | 0 | std::string(";\""); |
68 | | |
69 | | // when reporting the warning, print the source name only |
70 | 26.6k | m_errorReporter.warning(3420_error, {-1, -1, _sourceUnit.location().sourceName}, errorString); |
71 | 26.6k | } |
72 | 28.2k | if (!m_sourceUnit->annotation().useABICoderV2.set()) |
73 | 25.9k | m_sourceUnit->annotation().useABICoderV2 = true; |
74 | 28.2k | m_sourceUnit = nullptr; |
75 | 28.2k | } |
76 | | |
77 | | bool SyntaxChecker::visit(PragmaDirective const& _pragma) |
78 | 32.4k | { |
79 | 32.4k | solAssert(!_pragma.tokens().empty(), ""); |
80 | 32.4k | solAssert(_pragma.tokens().size() == _pragma.literals().size(), ""); |
81 | 32.4k | if (_pragma.tokens()[0] != Token::Identifier) |
82 | 161 | m_errorReporter.syntaxError(5226_error, _pragma.location(), "Invalid pragma \"" + _pragma.literals()[0] + "\""); |
83 | 32.2k | else if (_pragma.literals()[0] == "experimental") |
84 | 27.9k | { |
85 | 27.9k | solAssert(m_sourceUnit, ""); |
86 | 27.9k | std::vector<std::string> literals(_pragma.literals().begin() + 1, _pragma.literals().end()); |
87 | 27.9k | if (literals.empty()) |
88 | 20 | m_errorReporter.syntaxError( |
89 | 20 | 9679_error, |
90 | 20 | _pragma.location(), |
91 | 20 | "Experimental feature name is missing." |
92 | 20 | ); |
93 | 27.9k | else if (literals.size() > 1) |
94 | 53 | m_errorReporter.syntaxError( |
95 | 53 | 6022_error, |
96 | 53 | _pragma.location(), |
97 | 53 | "Stray arguments." |
98 | 53 | ); |
99 | 27.8k | else |
100 | 27.8k | { |
101 | 27.8k | std::string const literal = literals[0]; |
102 | 27.8k | if (literal.empty()) |
103 | 1 | m_errorReporter.syntaxError(3250_error, _pragma.location(), "Empty experimental feature name is invalid."); |
104 | 27.8k | else if (literal == "solidity") |
105 | 10 | m_errorReporter.syntaxError(3332_error, _pragma.location(), "The experimental Solidity prototype has been removed from the compiler."); |
106 | 27.8k | else if (!ExperimentalFeatureNames.count(literal)) |
107 | 121 | m_errorReporter.syntaxError(8491_error, _pragma.location(), "Unsupported experimental feature name."); |
108 | 27.7k | else if (m_sourceUnit->annotation().experimentalFeatures.count(ExperimentalFeatureNames.at(literal))) |
109 | 63 | m_errorReporter.syntaxError(1231_error, _pragma.location(), "Duplicate experimental feature name."); |
110 | 27.6k | else |
111 | 27.6k | { |
112 | 27.6k | auto feature = ExperimentalFeatureNames.at(literal); |
113 | 27.6k | m_sourceUnit->annotation().experimentalFeatures.insert(feature); |
114 | 27.6k | if (!ExperimentalFeatureWithoutWarning.count(feature)) |
115 | 10 | { |
116 | 10 | if (!m_experimental) |
117 | 10 | m_errorReporter.syntaxError( |
118 | 10 | 2816_error, |
119 | 10 | _pragma.location(), |
120 | 10 | "Experimental pragmas can only be used if experimental mode is enabled. To enable experimental mode, use the --experimental flag." |
121 | 10 | ); |
122 | 0 | else |
123 | 0 | m_errorReporter.warning(2264_error, _pragma.location(), "Experimental features are turned on. Do not use experimental features on live deployments."); |
124 | 10 | } |
125 | | |
126 | 27.6k | if (feature == ExperimentalFeature::ABIEncoderV2) |
127 | 316 | { |
128 | 316 | if (m_sourceUnit->annotation().useABICoderV2.set()) |
129 | 2 | { |
130 | 2 | if (!*m_sourceUnit->annotation().useABICoderV2) |
131 | 1 | m_errorReporter.syntaxError( |
132 | 1 | 8273_error, |
133 | 1 | _pragma.location(), |
134 | 1 | "ABI coder v1 has already been selected through \"pragma abicoder v1\"." |
135 | 1 | ); |
136 | 2 | } |
137 | 314 | else |
138 | 314 | m_sourceUnit->annotation().useABICoderV2 = true; |
139 | 316 | } |
140 | 27.6k | } |
141 | 27.8k | } |
142 | 27.9k | } |
143 | 4.32k | else if (_pragma.literals()[0] == "abicoder") |
144 | 2.20k | { |
145 | 2.20k | solAssert(m_sourceUnit, ""); |
146 | 2.20k | if ( |
147 | 2.20k | _pragma.literals().size() != 2 || |
148 | 2.12k | !std::set<std::string>{"v1", "v2"}.count(_pragma.literals()[1]) |
149 | 2.20k | ) |
150 | 216 | m_errorReporter.syntaxError( |
151 | 216 | 2745_error, |
152 | 216 | _pragma.location(), |
153 | 216 | "Expected either \"pragma abicoder v1\" or \"pragma abicoder v2\"." |
154 | 216 | ); |
155 | 1.98k | else if (m_sourceUnit->annotation().useABICoderV2.set()) |
156 | 54 | m_errorReporter.syntaxError( |
157 | 54 | 3845_error, |
158 | 54 | _pragma.location(), |
159 | 54 | "ABI coder has already been selected for this source unit." |
160 | 54 | ); |
161 | 1.93k | else |
162 | 1.93k | m_sourceUnit->annotation().useABICoderV2 = (_pragma.literals()[1] == "v2"); |
163 | | |
164 | 2.20k | if ( |
165 | 2.20k | _pragma.literals().size() > 1 && |
166 | 2.19k | _pragma.literals()[1] == "v1" |
167 | 2.20k | ) |
168 | 399 | m_errorReporter.warning( |
169 | 399 | 9511_error, |
170 | 399 | _pragma.location(), |
171 | 399 | "ABI coder v1 is deprecated and scheduled for removal. Use ABI coder v2 instead." |
172 | 399 | ); |
173 | 2.20k | } |
174 | 2.12k | else if (_pragma.literals()[0] == "solidity") |
175 | 1.70k | { |
176 | 1.70k | try |
177 | 1.70k | { |
178 | 1.70k | std::vector<Token> tokens(_pragma.tokens().begin() + 1, _pragma.tokens().end()); |
179 | 1.70k | std::vector<std::string> literals(_pragma.literals().begin() + 1, _pragma.literals().end()); |
180 | 1.70k | SemVerMatchExpressionParser parser(tokens, literals); |
181 | 1.70k | SemVerMatchExpression matchExpression = parser.parse(); |
182 | 1.70k | static SemVerVersion const currentVersion{std::string(VersionString)}; |
183 | 1.70k | solAssert(matchExpression.matches(currentVersion)); |
184 | 1.70k | m_versionPragmaFound = true; |
185 | 1.70k | } |
186 | 1.70k | catch (SemVerError const&) |
187 | 1.70k | { |
188 | | // An unparsable version pragma is an unrecoverable fatal error in the parser. |
189 | 0 | solAssert(false); |
190 | 0 | } |
191 | 1.70k | } |
192 | 417 | else |
193 | 417 | m_errorReporter.syntaxError(4936_error, _pragma.location(), "Unknown pragma \"" + _pragma.literals()[0] + "\""); |
194 | | |
195 | 32.4k | return true; |
196 | 32.4k | } |
197 | | |
198 | | bool SyntaxChecker::visit(ModifierDefinition const&) |
199 | 3.44k | { |
200 | 3.44k | m_placeholderFound = false; |
201 | 3.44k | return true; |
202 | 3.44k | } |
203 | | |
204 | | void SyntaxChecker::endVisit(ModifierDefinition const& _modifier) |
205 | 3.44k | { |
206 | 3.44k | if (_modifier.isImplemented() && !m_placeholderFound) |
207 | 33 | m_errorReporter.syntaxError(2883_error, _modifier.body().location(), "Modifier body does not contain '_'."); |
208 | | |
209 | 3.44k | if (_modifier.markedVirtual()) |
210 | 247 | m_errorReporter.warning( |
211 | 247 | 8429_error, |
212 | 247 | _modifier.location(), |
213 | 247 | "Virtual modifiers are deprecated and scheduled for removal." |
214 | 247 | ); |
215 | | |
216 | 3.44k | m_placeholderFound = false; |
217 | 3.44k | } |
218 | | |
219 | | void SyntaxChecker::checkSingleStatementVariableDeclaration(ASTNode const& _statement) |
220 | 49.2k | { |
221 | 49.2k | auto varDecl = dynamic_cast<VariableDeclarationStatement const*>(&_statement); |
222 | 49.2k | if (varDecl) |
223 | 8 | m_errorReporter.syntaxError(9079_error, _statement.location(), "Variable declarations can only be used inside blocks."); |
224 | 49.2k | } |
225 | | |
226 | | bool SyntaxChecker::visit(IfStatement const& _ifStatement) |
227 | 45.2k | { |
228 | 45.2k | checkSingleStatementVariableDeclaration(_ifStatement.trueStatement()); |
229 | 45.2k | if (Statement const* _statement = _ifStatement.falseStatement()) |
230 | 391 | checkSingleStatementVariableDeclaration(*_statement); |
231 | 45.2k | return true; |
232 | 45.2k | } |
233 | | |
234 | | bool SyntaxChecker::visit(WhileStatement const& _whileStatement) |
235 | 241 | { |
236 | 241 | m_inLoopDepth++; |
237 | 241 | checkSingleStatementVariableDeclaration(_whileStatement.body()); |
238 | 241 | return true; |
239 | 241 | } |
240 | | |
241 | | void SyntaxChecker::endVisit(WhileStatement const&) |
242 | 241 | { |
243 | 241 | m_inLoopDepth--; |
244 | 241 | } |
245 | | |
246 | | bool SyntaxChecker::visit(ForStatement const& _forStatement) |
247 | 3.37k | { |
248 | 3.37k | m_inLoopDepth++; |
249 | 3.37k | checkSingleStatementVariableDeclaration(_forStatement.body()); |
250 | 3.37k | return true; |
251 | 3.37k | } |
252 | | |
253 | | void SyntaxChecker::endVisit(ForStatement const&) |
254 | 3.37k | { |
255 | 3.37k | m_inLoopDepth--; |
256 | 3.37k | } |
257 | | |
258 | | bool SyntaxChecker::visit(Block const& _block) |
259 | 31.6k | { |
260 | 31.6k | if (_block.unchecked()) |
261 | 202 | { |
262 | 202 | if (m_uncheckedArithmetic) |
263 | 5 | m_errorReporter.syntaxError( |
264 | 5 | 1941_error, |
265 | 5 | _block.location(), |
266 | 5 | "\"unchecked\" blocks cannot be nested." |
267 | 5 | ); |
268 | | |
269 | 202 | m_uncheckedArithmetic = true; |
270 | 202 | } |
271 | 31.6k | return true; |
272 | 31.6k | } |
273 | | |
274 | | void SyntaxChecker::endVisit(Block const& _block) |
275 | 31.6k | { |
276 | 31.6k | if (_block.unchecked()) |
277 | 202 | m_uncheckedArithmetic = false; |
278 | 31.6k | } |
279 | | |
280 | | bool SyntaxChecker::visit(Continue const& _continueStatement) |
281 | 120 | { |
282 | 120 | if (m_inLoopDepth <= 0) |
283 | | // we're not in a for/while loop, report syntax error |
284 | 6 | m_errorReporter.syntaxError(4123_error, _continueStatement.location(), "\"continue\" has to be in a \"for\" or \"while\" loop."); |
285 | 120 | return true; |
286 | 120 | } |
287 | | |
288 | | bool SyntaxChecker::visit(Break const& _breakStatement) |
289 | 126 | { |
290 | 126 | if (m_inLoopDepth <= 0) |
291 | | // we're not in a for/while loop, report syntax error |
292 | 3 | m_errorReporter.syntaxError(6102_error, _breakStatement.location(), "\"break\" has to be in a \"for\" or \"while\" loop."); |
293 | 126 | return true; |
294 | 126 | } |
295 | | |
296 | | bool SyntaxChecker::visit(Throw const& _throwStatement) |
297 | 3 | { |
298 | 3 | m_errorReporter.syntaxError( |
299 | 3 | 4538_error, |
300 | 3 | _throwStatement.location(), |
301 | 3 | "\"throw\" is deprecated in favour of \"revert()\", \"require()\" and \"assert()\"." |
302 | 3 | ); |
303 | | |
304 | 3 | return true; |
305 | 3 | } |
306 | | |
307 | | bool SyntaxChecker::visit(Literal const& _literal) |
308 | 339k | { |
309 | 339k | size_t invalidSequence; |
310 | 339k | if ((_literal.token() == Token::UnicodeStringLiteral) && !validateUTF8(_literal.value(), invalidSequence)) |
311 | 140 | m_errorReporter.syntaxError( |
312 | 140 | 8452_error, |
313 | 140 | _literal.location(), |
314 | 140 | "Contains invalid UTF-8 sequence at position " + toString(invalidSequence) + "." |
315 | 140 | ); |
316 | | |
317 | 339k | if (_literal.token() != Token::Number) |
318 | 49.7k | return true; |
319 | | |
320 | 290k | ASTString const& value = _literal.value(); |
321 | 290k | solAssert(!value.empty(), ""); |
322 | | |
323 | | // Generic checks no matter what base this number literal is of: |
324 | 290k | if (value.back() == '_') |
325 | 224 | { |
326 | 224 | m_errorReporter.syntaxError(2090_error, _literal.location(), "Invalid use of underscores in number literal. No trailing underscores allowed."); |
327 | 224 | return true; |
328 | 224 | } |
329 | | |
330 | 289k | if (value.find("__") != ASTString::npos) |
331 | 148 | { |
332 | 148 | m_errorReporter.syntaxError(2990_error, _literal.location(), "Invalid use of underscores in number literal. Only one consecutive underscore between digits is allowed."); |
333 | 148 | return true; |
334 | 148 | } |
335 | | |
336 | 289k | if (!_literal.isHexNumber()) // decimal literal |
337 | 282k | { |
338 | 282k | if (value.find("._") != ASTString::npos) |
339 | 599 | m_errorReporter.syntaxError(3891_error, _literal.location(), "Invalid use of underscores in number literal. No underscores in front of the fraction part allowed."); |
340 | | |
341 | 282k | if (value.find("_.") != ASTString::npos) |
342 | 321 | m_errorReporter.syntaxError(1023_error, _literal.location(), "Invalid use of underscores in number literal. No underscores in front of the fraction part allowed."); |
343 | | |
344 | 282k | if (value.find("_e") != ASTString::npos) |
345 | 377 | m_errorReporter.syntaxError(6415_error, _literal.location(), "Invalid use of underscores in number literal. No underscore at the end of the mantissa allowed."); |
346 | | |
347 | 282k | if (value.find("e_") != ASTString::npos) |
348 | 102 | m_errorReporter.syntaxError(6165_error, _literal.location(), "Invalid use of underscores in number literal. No underscore in front of exponent allowed."); |
349 | 282k | } |
350 | | |
351 | 289k | return true; |
352 | 289k | } |
353 | | |
354 | | bool SyntaxChecker::visit(UnaryOperation const& _operation) |
355 | 47.1k | { |
356 | 47.1k | solAssert(_operation.getOperator() != Token::Add); |
357 | 47.1k | return true; |
358 | 47.1k | } |
359 | | |
360 | | bool SyntaxChecker::visit(InlineAssembly const& _inlineAssembly) |
361 | 4.34k | { |
362 | 4.34k | if (_inlineAssembly.flags()) |
363 | 44 | for (auto flag: *_inlineAssembly.flags()) |
364 | 88 | { |
365 | 88 | if (*flag == "memory-safe") |
366 | 31 | { |
367 | 31 | if (_inlineAssembly.annotation().markedMemorySafe) |
368 | 2 | m_errorReporter.syntaxError( |
369 | 2 | 7026_error, |
370 | 2 | _inlineAssembly.location(), |
371 | 2 | "Inline assembly marked memory-safe multiple times." |
372 | 2 | ); |
373 | 31 | _inlineAssembly.annotation().markedMemorySafe = true; |
374 | 31 | } |
375 | 57 | else |
376 | 57 | m_errorReporter.warning( |
377 | 57 | 4430_error, |
378 | 57 | _inlineAssembly.location(), |
379 | 57 | "Unknown inline assembly flag: \"" + *flag + "\"" |
380 | 57 | ); |
381 | 88 | } |
382 | | |
383 | 4.34k | if (!m_useYulOptimizer) |
384 | 1.85k | return false; |
385 | | |
386 | 2.49k | if (yul::MSizeFinder::containsMSize(_inlineAssembly.dialect(), _inlineAssembly.operations().root())) |
387 | 0 | m_errorReporter.syntaxError( |
388 | 0 | 6553_error, |
389 | 0 | _inlineAssembly.location(), |
390 | 0 | "The msize instruction cannot be used when the Yul optimizer is activated because " |
391 | 0 | "it can change its semantics. Either disable the Yul optimizer or do not use the instruction." |
392 | 0 | ); |
393 | | |
394 | 2.49k | return false; |
395 | 4.34k | } |
396 | | |
397 | | bool SyntaxChecker::visit(PlaceholderStatement const& _placeholder) |
398 | 989 | { |
399 | 989 | if (m_uncheckedArithmetic) |
400 | 1 | m_errorReporter.syntaxError( |
401 | 1 | 2573_error, |
402 | 1 | _placeholder.location(), |
403 | 1 | "The placeholder statement \"_\" cannot be used inside an \"unchecked\" block." |
404 | 1 | ); |
405 | | |
406 | 989 | m_placeholderFound = true; |
407 | 989 | return true; |
408 | 989 | } |
409 | | |
410 | | bool SyntaxChecker::visit(ContractDefinition const& _contract) |
411 | 30.1k | { |
412 | 30.1k | m_currentContractKind = _contract.contractKind(); |
413 | | |
414 | 30.1k | ASTString const& contractName = _contract.name(); |
415 | 30.1k | for (FunctionDefinition const* function: _contract.definedFunctions()) |
416 | 27.8k | if (function->name() == contractName) |
417 | 1 | m_errorReporter.syntaxError( |
418 | 1 | 5796_error, |
419 | 1 | function->location(), |
420 | 1 | "Functions are not allowed to have the same name as the contract. " |
421 | 1 | "If you intend this to be a constructor, use \"constructor(...) { ... }\" to define it." |
422 | 1 | ); |
423 | 30.1k | return true; |
424 | 30.1k | } |
425 | | |
426 | | void SyntaxChecker::endVisit(ContractDefinition const&) |
427 | 30.1k | { |
428 | 30.1k | m_currentContractKind = std::nullopt; |
429 | 30.1k | } |
430 | | |
431 | | bool SyntaxChecker::visit(UsingForDirective const& _usingFor) |
432 | 779 | { |
433 | 779 | if (!_usingFor.usesBraces()) |
434 | 779 | solAssert( |
435 | 779 | _usingFor.functionsAndOperators().size() == 1 && |
436 | 779 | !std::get<1>(_usingFor.functionsAndOperators().front()) |
437 | 779 | ); |
438 | | |
439 | 779 | if (!m_currentContractKind && !_usingFor.typeName()) |
440 | 12 | m_errorReporter.syntaxError( |
441 | 12 | 8118_error, |
442 | 12 | _usingFor.location(), |
443 | 12 | "The type has to be specified explicitly at file level (cannot use '*')." |
444 | 12 | ); |
445 | 767 | else if (_usingFor.usesBraces() && !_usingFor.typeName()) |
446 | 10 | m_errorReporter.syntaxError( |
447 | 10 | 3349_error, |
448 | 10 | _usingFor.location(), |
449 | 10 | "The type has to be specified explicitly when attaching specific functions." |
450 | 10 | ); |
451 | 779 | if (_usingFor.global() && !_usingFor.typeName()) |
452 | 4 | m_errorReporter.syntaxError( |
453 | 4 | 2854_error, |
454 | 4 | _usingFor.location(), |
455 | 4 | "Can only globally attach functions to specific types." |
456 | 4 | ); |
457 | 779 | if (_usingFor.global() && m_currentContractKind) |
458 | 8 | m_errorReporter.syntaxError( |
459 | 8 | 3367_error, |
460 | 8 | _usingFor.location(), |
461 | 8 | "\"global\" can only be used at file level." |
462 | 8 | ); |
463 | 779 | if (m_currentContractKind == ContractKind::Interface) |
464 | 3 | m_errorReporter.syntaxError( |
465 | 3 | 9088_error, |
466 | 3 | _usingFor.location(), |
467 | 3 | "The \"using for\" directive is not allowed inside interfaces." |
468 | 3 | ); |
469 | | |
470 | 779 | return true; |
471 | 779 | } |
472 | | |
473 | | bool SyntaxChecker::visit(FunctionDefinition const& _function) |
474 | 31.3k | { |
475 | 31.3k | if (!_function.isFree() && !_function.isConstructor() && _function.noVisibilitySpecified()) |
476 | 1.53k | { |
477 | 1.53k | std::string suggestedVisibility = |
478 | 1.53k | _function.isFallback() || |
479 | 1.50k | _function.isReceive() || |
480 | 1.44k | m_currentContractKind == ContractKind::Interface |
481 | 1.53k | ? "external" : "public"; |
482 | 1.53k | m_errorReporter.syntaxError( |
483 | 1.53k | 4937_error, |
484 | 1.53k | _function.location(), |
485 | 1.53k | "No visibility specified. Did you intend to add \"" + suggestedVisibility + "\"?" |
486 | 1.53k | ); |
487 | 1.53k | } |
488 | 29.8k | else if (_function.isFree()) |
489 | 3.53k | { |
490 | 3.53k | if (!_function.noVisibilitySpecified()) |
491 | 181 | m_errorReporter.syntaxError( |
492 | 181 | 4126_error, |
493 | 181 | _function.location(), |
494 | 181 | "Free functions cannot have visibility." |
495 | 181 | ); |
496 | 3.53k | if (!_function.isImplemented()) |
497 | 500 | m_errorReporter.typeError(4668_error, _function.location(), "Free functions must be implemented."); |
498 | 3.53k | } |
499 | | |
500 | 31.3k | if (m_currentContractKind == ContractKind::Interface && !_function.modifiers().empty()) |
501 | 65 | m_errorReporter.syntaxError(5842_error, _function.location(), "Functions in interfaces cannot have modifiers."); |
502 | 31.2k | else if (!_function.isImplemented() && !_function.modifiers().empty()) |
503 | 202 | m_errorReporter.syntaxError(2668_error, _function.location(), "Functions without implementation cannot have modifiers."); |
504 | | |
505 | 31.3k | return true; |
506 | 31.3k | } |
507 | | |
508 | | bool SyntaxChecker::visit(FunctionTypeName const& _node) |
509 | 1.27k | { |
510 | 1.27k | for (auto const& decl: _node.parameterTypeList()->parameters()) |
511 | 625 | if (!decl->name().empty()) |
512 | 127 | m_errorReporter.warning(6162_error, decl->location(), "Naming function type parameters is deprecated."); |
513 | | |
514 | 1.27k | for (auto const& decl: _node.returnParameterTypeList()->parameters()) |
515 | 481 | if (!decl->name().empty()) |
516 | 8 | m_errorReporter.syntaxError(7304_error, decl->location(), "Return parameters in function types may not be named."); |
517 | | |
518 | 1.27k | return true; |
519 | 1.27k | } |
520 | | |
521 | | bool SyntaxChecker::visit(StructDefinition const& _struct) |
522 | 9.78k | { |
523 | 9.78k | if (_struct.members().empty()) |
524 | 92 | m_errorReporter.syntaxError(5306_error, _struct.location(), "Defining empty structs is disallowed."); |
525 | | |
526 | 9.78k | return true; |
527 | 9.78k | } |
528 | | |