solidity/libsolidity/ast/AST.cpp

831 lines
22 KiB
C++
Raw Normal View History

/*
2019-02-13 15:56:46 +00:00
This file is part of solidity.
2019-02-13 15:56:46 +00:00
solidity 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.
2019-02-13 15:56:46 +00:00
solidity 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.
2019-02-13 15:56:46 +00:00
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
/**
* @author Christian <c@ethdev.com>
* @date 2014
* Solidity abstract syntax tree.
*/
2015-10-20 22:21:52 +00:00
#include <libsolidity/ast/AST.h>
2018-12-17 14:33:15 +00:00
2015-10-20 22:21:52 +00:00
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/ast/AST_accept.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolutil/Keccak256.h>
#include <boost/algorithm/string.hpp>
2020-04-01 03:04:29 +00:00
#include <algorithm>
#include <functional>
2020-04-01 03:04:29 +00:00
#include <utility>
2014-10-24 17:06:30 +00:00
using namespace std;
2019-12-11 16:31:36 +00:00
using namespace solidity;
using namespace solidity::frontend;
2014-10-24 17:06:30 +00:00
2020-04-01 03:04:29 +00:00
ASTNode::ASTNode(int64_t _id, SourceLocation _location):
m_id(static_cast<size_t>(_id)),
2020-04-01 03:04:29 +00:00
m_location(std::move(_location))
2014-10-16 12:08:54 +00:00
{
2014-10-23 17:22:30 +00:00
}
2015-09-21 16:55:58 +00:00
ASTAnnotation& ASTNode::annotation() const
{
if (!m_annotation)
2019-11-27 17:03:09 +00:00
m_annotation = make_unique<ASTAnnotation>();
2015-09-21 16:55:58 +00:00
return *m_annotation;
}
2015-12-15 14:46:03 +00:00
SourceUnitAnnotation& SourceUnit::annotation() const
{
return initAnnotation<SourceUnitAnnotation>();
2015-12-15 14:46:03 +00:00
}
set<SourceUnit const*> SourceUnit::referencedSourceUnits(bool _recurse, set<SourceUnit const*> _skipList) const
2017-07-12 23:08:28 +00:00
{
set<SourceUnit const*> sourceUnits;
2017-07-12 23:08:28 +00:00
for (ImportDirective const* importDirective: filteredNodes<ImportDirective>(nodes()))
{
auto const& sourceUnit = importDirective->annotation().sourceUnit;
if (!_skipList.count(sourceUnit))
{
_skipList.insert(sourceUnit);
sourceUnits.insert(sourceUnit);
if (_recurse)
2017-07-13 23:17:52 +00:00
sourceUnits += sourceUnit->referencedSourceUnits(true, _skipList);
}
2017-07-12 23:08:28 +00:00
}
return sourceUnits;
}
2015-12-09 16:35:20 +00:00
ImportAnnotation& ImportDirective::annotation() const
{
return initAnnotation<ImportAnnotation>();
2015-12-09 16:35:20 +00:00
}
2015-12-15 14:46:03 +00:00
TypePointer ImportDirective::type() const
{
solAssert(!!annotation().sourceUnit, "");
return TypeProvider::module(*annotation().sourceUnit);
2015-12-15 14:46:03 +00:00
}
vector<VariableDeclaration const*> ContractDefinition::stateVariablesIncludingInherited() const
{
vector<VariableDeclaration const*> stateVars;
for (auto const& contract: annotation().linearizedBaseContracts)
for (auto var: contract->stateVariables())
if (*contract == *this || var->isVisibleInDerivedContracts())
stateVars.push_back(var);
return stateVars;
}
bool ContractDefinition::derivesFrom(ContractDefinition const& _base) const
{
return util::contains(annotation().linearizedBaseContracts, &_base);
}
2020-04-08 22:08:49 +00:00
map<util::FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions(bool _includeInheritedFunctions) const
{
2020-04-08 22:08:49 +00:00
auto exportedFunctionList = interfaceFunctionList(_includeInheritedFunctions);
2019-12-11 16:31:36 +00:00
map<util::FixedHash<4>, FunctionTypePointer> exportedFunctions;
for (auto const& it: exportedFunctionList)
exportedFunctions.insert(it);
2015-09-10 08:17:17 +00:00
solAssert(
exportedFunctionList.size() == exportedFunctions.size(),
"Hash collision at Function Definition Hash calculation"
);
return exportedFunctions;
}
2015-08-31 16:44:29 +00:00
FunctionDefinition const* ContractDefinition::constructor() const
2014-12-12 15:49:26 +00:00
{
for (FunctionDefinition const* f: definedFunctions())
if (f->isConstructor())
return f;
2014-12-12 15:49:26 +00:00
return nullptr;
}
bool ContractDefinition::canBeDeployed() const
{
2020-06-10 16:19:42 +00:00
return !abstract() && !isInterface();
}
2015-08-31 16:44:29 +00:00
FunctionDefinition const* ContractDefinition::fallbackFunction() const
2015-01-29 21:50:20 +00:00
{
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
for (FunctionDefinition const* f: contract->definedFunctions())
2017-07-27 19:55:55 +00:00
if (f->isFallback())
return f;
2015-01-29 21:50:20 +00:00
return nullptr;
}
FunctionDefinition const* ContractDefinition::receiveFunction() const
{
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
for (FunctionDefinition const* f: contract->definedFunctions())
if (f->isReceive())
return f;
return nullptr;
}
vector<EventDefinition const*> const& ContractDefinition::interfaceEvents() const
{
return m_interfaceEvents.init([&]{
set<string> eventsSeen;
vector<EventDefinition const*> interfaceEvents;
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
for (EventDefinition const* e: contract->events())
2017-08-25 09:41:48 +00:00
{
/// NOTE: this requires the "internal" version of an Event,
/// though here internal strictly refers to visibility,
/// and not to function encoding (jump vs. call)
auto const& function = e->functionType(true);
solAssert(function, "");
string eventSignature = function->externalSignature();
if (eventsSeen.count(eventSignature) == 0)
{
2017-08-25 09:41:48 +00:00
eventsSeen.insert(eventSignature);
interfaceEvents.push_back(e);
}
2017-08-25 09:41:48 +00:00
}
return interfaceEvents;
});
}
2020-04-08 22:08:49 +00:00
vector<pair<util::FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::interfaceFunctionList(bool _includeInheritedFunctions) const
{
return m_interfaceFunctionList[_includeInheritedFunctions].init([&]{
2015-03-01 03:34:39 +00:00
set<string> signaturesSeen;
vector<pair<util::FixedHash<4>, FunctionTypePointer>> interfaceFunctionList;
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
{
2020-04-08 22:08:49 +00:00
if (_includeInheritedFunctions == false && contract != this)
continue;
vector<FunctionTypePointer> functions;
for (FunctionDefinition const* f: contract->definedFunctions())
if (f->isPartOfExternalInterface())
functions.push_back(TypeProvider::function(*f, FunctionType::Kind::External));
for (VariableDeclaration const* v: contract->stateVariables())
if (v->isPartOfExternalInterface())
functions.push_back(TypeProvider::function(*v));
for (FunctionTypePointer const& fun: functions)
2015-03-01 03:34:39 +00:00
{
if (!fun->interfaceFunctionType())
// Fails hopefully because we already registered the error
continue;
string functionSignature = fun->externalSignature();
if (signaturesSeen.count(functionSignature) == 0)
{
2015-03-01 03:34:39 +00:00
signaturesSeen.insert(functionSignature);
2019-12-11 16:31:36 +00:00
util::FixedHash<4> hash(util::keccak256(functionSignature));
interfaceFunctionList.emplace_back(hash, fun);
}
2015-03-01 03:34:39 +00:00
}
}
return interfaceFunctionList;
});
}
uint64_t ContractDefinition::interfaceId() const
{
uint64_t result{0};
for (auto const& function: interfaceFunctionList(false))
result ^= util::fromBigEndian<uint64_t>(function.first.ref());
return result;
}
2015-11-19 17:02:04 +00:00
TypePointer ContractDefinition::type() const
2015-02-10 12:40:21 +00:00
{
return TypeProvider::typeType(TypeProvider::contract(*this));
}
2015-09-21 16:55:58 +00:00
ContractDefinitionAnnotation& ContractDefinition::annotation() const
{
return initAnnotation<ContractDefinitionAnnotation>();
2015-09-21 16:55:58 +00:00
}
ContractDefinition const* ContractDefinition::superContract(ContractDefinition const& _mostDerivedContract) const
{
auto const& hierarchy = _mostDerivedContract.annotation().linearizedBaseContracts;
auto it = find(hierarchy.begin(), hierarchy.end(), this);
solAssert(it != hierarchy.end(), "Base not found in inheritance hierarchy.");
++it;
if (it == hierarchy.end())
return nullptr;
else
{
solAssert(*it != this, "");
return *it;
}
}
FunctionDefinition const* ContractDefinition::nextConstructor(ContractDefinition const& _mostDerivedContract) const
{
ContractDefinition const* next = superContract(_mostDerivedContract);
if (next == nullptr)
return nullptr;
for (ContractDefinition const* c: _mostDerivedContract.annotation().linearizedBaseContracts)
if (c == next || next == nullptr)
{
if (c->constructor())
return c->constructor();
next = nullptr;
}
return nullptr;
}
2015-09-21 16:55:58 +00:00
TypeNameAnnotation& TypeName::annotation() const
{
return initAnnotation<TypeNameAnnotation>();
2015-09-21 16:55:58 +00:00
}
2015-11-19 17:02:04 +00:00
TypePointer StructDefinition::type() const
{
solAssert(annotation().recursive.has_value(), "Requested struct type before DeclarationTypeChecker.");
return TypeProvider::typeType(TypeProvider::structType(*this, DataLocation::Storage));
}
StructDeclarationAnnotation& StructDefinition::annotation() const
{
return initAnnotation<StructDeclarationAnnotation>();
}
2015-11-19 17:02:04 +00:00
TypePointer EnumValue::type() const
2014-12-03 06:46:55 +00:00
{
auto parentDef = dynamic_cast<EnumDefinition const*>(scope());
solAssert(parentDef, "Enclosing Scope of EnumValue was not set");
return TypeProvider::enumType(*parentDef);
2014-12-03 06:46:55 +00:00
}
2015-11-19 17:02:04 +00:00
TypePointer EnumDefinition::type() const
2015-02-09 17:08:56 +00:00
{
return TypeProvider::typeType(TypeProvider::enumType(*this));
2015-02-09 17:08:56 +00:00
}
TypeDeclarationAnnotation& EnumDefinition::annotation() const
{
return initAnnotation<TypeDeclarationAnnotation>();
}
bool FunctionDefinition::libraryFunction() const
{
if (auto const* contractDef = dynamic_cast<ContractDefinition const*>(scope()))
return contractDef->isLibrary();
return false;
}
Visibility FunctionDefinition::defaultVisibility() const
{
solAssert(!isConstructor(), "");
2020-06-16 01:35:09 +00:00
return isFree() ? Visibility::Internal : Declaration::defaultVisibility();
}
FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
2017-01-10 15:26:13 +00:00
{
if (_internal)
{
switch (visibility())
{
2019-12-10 14:54:09 +00:00
case Visibility::Default:
2017-01-10 15:26:13 +00:00
solAssert(false, "visibility() should not return Default");
2019-12-10 14:54:09 +00:00
case Visibility::Private:
case Visibility::Internal:
case Visibility::Public:
return TypeProvider::function(*this, FunctionType::Kind::Internal);
2019-12-10 14:54:09 +00:00
case Visibility::External:
2017-01-10 15:26:13 +00:00
return {};
}
}
else
{
switch (visibility())
{
2019-12-10 14:54:09 +00:00
case Visibility::Default:
2017-01-10 15:26:13 +00:00
solAssert(false, "visibility() should not return Default");
2019-12-10 14:54:09 +00:00
case Visibility::Private:
case Visibility::Internal:
2017-01-10 15:26:13 +00:00
return {};
2019-12-10 14:54:09 +00:00
case Visibility::Public:
case Visibility::External:
return TypeProvider::function(*this, FunctionType::Kind::External);
2017-01-10 15:26:13 +00:00
}
}
// To make the compiler happy
return {};
}
2015-11-19 17:02:04 +00:00
TypePointer FunctionDefinition::type() const
{
2019-12-10 14:54:09 +00:00
solAssert(visibility() != Visibility::External, "");
return TypeProvider::function(*this, FunctionType::Kind::Internal);
}
TypePointer FunctionDefinition::typeViaContractName() const
{
2020-05-04 16:38:00 +00:00
if (libraryFunction())
2020-05-25 17:30:17 +00:00
{
if (isPublic())
2020-05-26 08:48:17 +00:00
return FunctionType(*this).asExternallyCallableFunction(true);
2020-05-25 17:30:17 +00:00
else
return TypeProvider::function(*this, FunctionType::Kind::Internal);
}
else
return TypeProvider::function(*this, FunctionType::Kind::Declaration);
}
string FunctionDefinition::externalSignature() const
{
return TypeProvider::function(*this)->externalSignature();
}
string FunctionDefinition::externalIdentifierHex() const
{
return TypeProvider::function(*this)->externalIdentifierHex();
}
2015-10-26 14:13:36 +00:00
FunctionDefinitionAnnotation& FunctionDefinition::annotation() const
{
return initAnnotation<FunctionDefinitionAnnotation>();
2015-10-26 14:13:36 +00:00
}
FunctionDefinition const& FunctionDefinition::resolveVirtual(
ContractDefinition const& _mostDerivedContract,
ContractDefinition const* _searchStart
) const
{
solAssert(!isConstructor(), "");
// If we are not doing super-lookup and the function is not virtual, we can stop here.
if (_searchStart == nullptr && !virtualSemantics())
return *this;
2020-05-04 16:38:00 +00:00
solAssert(!isFree(), "");
solAssert(isOrdinary(), "");
solAssert(!libraryFunction(), "");
2020-05-26 08:48:17 +00:00
FunctionType const* functionType = TypeProvider::function(*this)->asExternallyCallableFunction(false);
for (ContractDefinition const* c: _mostDerivedContract.annotation().linearizedBaseContracts)
{
if (_searchStart != nullptr && c != _searchStart)
continue;
_searchStart = nullptr;
for (FunctionDefinition const* function: c->definedFunctions())
if (
function->name() == name() &&
!function->isConstructor() &&
2020-05-26 08:48:17 +00:00
FunctionType(*function).asExternallyCallableFunction(false)->hasEqualParameterTypes(*functionType)
)
return *function;
}
solAssert(false, "Virtual function " + name() + " not found.");
return *this; // not reached
}
2015-11-19 17:02:04 +00:00
TypePointer ModifierDefinition::type() const
{
return TypeProvider::modifier(*this);
}
2015-10-26 14:13:36 +00:00
ModifierDefinitionAnnotation& ModifierDefinition::annotation() const
{
return initAnnotation<ModifierDefinitionAnnotation>();
2015-10-26 14:13:36 +00:00
}
ModifierDefinition const& ModifierDefinition::resolveVirtual(
ContractDefinition const& _mostDerivedContract,
ContractDefinition const* _searchStart
) const
{
solAssert(_searchStart == nullptr, "Used super in connection with modifiers.");
// If we are not doing super-lookup and the modifier is not virtual, we can stop here.
if (_searchStart == nullptr && !virtualSemantics())
return *this;
solAssert(!dynamic_cast<ContractDefinition const&>(*scope()).isLibrary(), "");
for (ContractDefinition const* c: _mostDerivedContract.annotation().linearizedBaseContracts)
{
if (_searchStart != nullptr && c != _searchStart)
continue;
_searchStart = nullptr;
for (ModifierDefinition const* modifier: c->functionModifiers())
if (modifier->name() == name())
return *modifier;
}
solAssert(false, "Virtual modifier " + name() + " not found.");
return *this; // not reached
}
2015-11-19 17:02:04 +00:00
TypePointer EventDefinition::type() const
{
return TypeProvider::function(*this);
}
2015-03-08 22:26:36 +00:00
FunctionTypePointer EventDefinition::functionType(bool _internal) const
2017-01-10 17:55:36 +00:00
{
if (_internal)
return TypeProvider::function(*this);
2017-01-10 17:55:36 +00:00
else
return nullptr;
2017-01-10 17:55:36 +00:00
}
2015-10-26 14:13:36 +00:00
EventDefinitionAnnotation& EventDefinition::annotation() const
{
return initAnnotation<EventDefinitionAnnotation>();
2015-10-26 14:13:36 +00:00
}
2015-09-21 16:55:58 +00:00
UserDefinedTypeNameAnnotation& UserDefinedTypeName::annotation() const
{
return initAnnotation<UserDefinedTypeNameAnnotation>();
2015-09-21 16:55:58 +00:00
}
SourceUnit const& Scopable::sourceUnit() const
{
ASTNode const* s = scope();
solAssert(s, "");
// will not always be a declaration
while (dynamic_cast<Scopable const*>(s) && dynamic_cast<Scopable const*>(s)->scope())
s = dynamic_cast<Scopable const*>(s)->scope();
return dynamic_cast<SourceUnit const&>(*s);
}
CallableDeclaration const* Scopable::functionOrModifierDefinition() const
{
ASTNode const* s = scope();
solAssert(s, "");
while (dynamic_cast<Scopable const*>(s))
{
if (auto funDef = dynamic_cast<FunctionDefinition const*>(s))
return funDef;
if (auto modDef = dynamic_cast<ModifierDefinition const*>(s))
return modDef;
s = dynamic_cast<Scopable const*>(s)->scope();
}
return nullptr;
}
string Scopable::sourceUnitName() const
{
return *sourceUnit().annotation().path;
}
2020-09-26 22:00:56 +00:00
bool Declaration::isEnumValue() const
{
solAssert(scope(), "");
return dynamic_cast<EnumDefinition const*>(scope());
}
bool Declaration::isStructMember() const
{
solAssert(scope(), "");
return dynamic_cast<StructDefinition const*>(scope());
}
bool Declaration::isEventParameter() const
{
solAssert(scope(), "");
return dynamic_cast<EventDefinition const*>(scope());
}
2019-12-19 23:04:46 +00:00
DeclarationAnnotation& Declaration::annotation() const
{
return initAnnotation<DeclarationAnnotation>();
2019-12-19 23:04:46 +00:00
}
bool VariableDeclaration::isLValue() const
{
// Constant declared variables are Read-Only
return !isConstant();
}
2018-02-09 15:53:52 +00:00
bool VariableDeclaration::isLocalVariable() const
{
auto s = scope();
return
2018-08-07 13:58:34 +00:00
dynamic_cast<FunctionTypeName const*>(s) ||
2018-02-09 15:53:52 +00:00
dynamic_cast<CallableDeclaration const*>(s) ||
dynamic_cast<Block const*>(s) ||
2019-09-02 14:17:02 +00:00
dynamic_cast<TryCatchClause const*>(s) ||
2018-02-09 15:53:52 +00:00
dynamic_cast<ForStatement const*>(s);
}
2019-09-05 18:02:34 +00:00
bool VariableDeclaration::isCallableOrCatchParameter() const
{
2019-09-05 18:02:34 +00:00
if (isReturnParameter() || isTryCatchParameter())
2018-08-07 13:58:34 +00:00
return true;
vector<ASTPointer<VariableDeclaration>> const* parameters = nullptr;
if (auto const* funTypeName = dynamic_cast<FunctionTypeName const*>(scope()))
parameters = &funTypeName->parameterTypes();
else if (auto const* callable = dynamic_cast<CallableDeclaration const*>(scope()))
parameters = &callable->parameters();
if (parameters)
for (auto const& variable: *parameters)
if (variable.get() == this)
return true;
return false;
}
2017-07-06 09:05:05 +00:00
bool VariableDeclaration::isLocalOrReturn() const
{
2019-09-05 18:02:34 +00:00
return isReturnParameter() || (isLocalVariable() && !isCallableOrCatchParameter());
2017-07-06 09:05:05 +00:00
}
bool VariableDeclaration::isReturnParameter() const
{
2018-08-07 13:58:34 +00:00
vector<ASTPointer<VariableDeclaration>> const* returnParameters = nullptr;
if (auto const* funTypeName = dynamic_cast<FunctionTypeName const*>(scope()))
returnParameters = &funTypeName->returnParameterTypes();
else if (auto const* callable = dynamic_cast<CallableDeclaration const*>(scope()))
if (callable->returnParameterList())
returnParameters = &callable->returnParameterList()->parameters();
if (returnParameters)
for (auto const& variable: *returnParameters)
2017-07-06 09:05:05 +00:00
if (variable.get() == this)
return true;
return false;
}
2019-09-05 18:02:34 +00:00
bool VariableDeclaration::isTryCatchParameter() const
{
return dynamic_cast<TryCatchClause const*>(scope());
}
bool VariableDeclaration::isExternalCallableParameter() const
{
2019-09-05 18:02:34 +00:00
if (!isCallableOrCatchParameter())
return false;
2018-08-07 13:58:34 +00:00
if (auto const* callable = dynamic_cast<CallableDeclaration const*>(scope()))
2019-12-10 14:54:09 +00:00
if (callable->visibility() == Visibility::External)
2018-08-07 13:58:34 +00:00
return !isReturnParameter();
return false;
}
bool VariableDeclaration::isPublicCallableParameter() const
{
if (!isCallableOrCatchParameter())
return false;
if (auto const* callable = dynamic_cast<CallableDeclaration const*>(scope()))
if (callable->visibility() == Visibility::Public)
return !isReturnParameter();
return false;
}
2018-08-07 13:58:34 +00:00
bool VariableDeclaration::isInternalCallableParameter() const
{
2019-09-05 18:02:34 +00:00
if (!isCallableOrCatchParameter())
2018-08-07 13:58:34 +00:00
return false;
if (auto const* funTypeName = dynamic_cast<FunctionTypeName const*>(scope()))
2019-12-10 14:54:09 +00:00
return funTypeName->visibility() == Visibility::Internal;
2018-08-07 13:58:34 +00:00
else if (auto const* callable = dynamic_cast<CallableDeclaration const*>(scope()))
2019-12-10 14:54:09 +00:00
return callable->visibility() <= Visibility::Internal;
2018-08-07 13:58:34 +00:00
return false;
}
bool VariableDeclaration::isConstructorParameter() const
{
if (!isCallableOrCatchParameter())
return false;
if (auto const* function = dynamic_cast<FunctionDefinition const*>(scope()))
return function->isConstructor();
return false;
}
2018-08-07 13:58:34 +00:00
bool VariableDeclaration::isLibraryFunctionParameter() const
{
2019-09-05 18:02:34 +00:00
if (!isCallableOrCatchParameter())
2018-08-07 13:58:34 +00:00
return false;
if (auto const* funDef = dynamic_cast<FunctionDefinition const*>(scope()))
2020-05-04 16:38:00 +00:00
return funDef->libraryFunction();
return false;
2018-08-07 13:58:34 +00:00
}
bool VariableDeclaration::hasReferenceOrMappingType() const
{
2020-07-15 17:50:59 +00:00
solAssert(typeName().annotation().type, "Can only be called after reference resolution");
Type const* type = typeName().annotation().type;
return type->category() == Type::Category::Mapping || dynamic_cast<ReferenceType const*>(type);
2018-08-07 13:58:34 +00:00
}
bool VariableDeclaration::isStateVariable() const
{
return dynamic_cast<ContractDefinition const*>(scope());
}
2018-08-07 13:58:34 +00:00
set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() const
{
using Location = VariableDeclaration::Location;
if (!hasReferenceOrMappingType() || isStateVariable() || isEventParameter())
return set<Location>{ Location::Unspecified };
2019-09-05 18:02:34 +00:00
else if (isCallableOrCatchParameter())
2018-08-07 13:58:34 +00:00
{
set<Location> locations{ Location::Memory };
if (
isConstructorParameter() ||
isInternalCallableParameter() ||
isLibraryFunctionParameter() ||
isTryCatchParameter()
)
2018-08-07 13:58:34 +00:00
locations.insert(Location::Storage);
if (!isTryCatchParameter() && !isConstructorParameter())
2020-05-25 17:30:17 +00:00
locations.insert(Location::CallData);
2018-08-07 13:58:34 +00:00
return locations;
}
else if (isLocalVariable())
2020-07-15 17:50:59 +00:00
// Further restrictions will be imposed later on.
return set<Location>{ Location::Memory, Location::Storage, Location::CallData };
2018-08-07 13:58:34 +00:00
else
// Struct members etc.
return set<Location>{ Location::Unspecified };
2018-08-07 13:58:34 +00:00
}
string VariableDeclaration::externalIdentifierHex() const
{
solAssert(isStateVariable() && isPublic(), "Can only be called for public state variables");
return TypeProvider::function(*this)->externalIdentifierHex();
}
2015-11-19 17:02:04 +00:00
TypePointer VariableDeclaration::type() const
2014-10-13 16:22:15 +00:00
{
return annotation().type;
2014-10-16 12:08:54 +00:00
}
2015-09-21 16:55:58 +00:00
FunctionTypePointer VariableDeclaration::functionType(bool _internal) const
2017-01-10 15:26:13 +00:00
{
if (_internal)
return nullptr;
2017-01-10 15:26:13 +00:00
switch (visibility())
{
2019-12-10 14:54:09 +00:00
case Visibility::Default:
2017-01-10 15:26:13 +00:00
solAssert(false, "visibility() should not return Default");
2019-12-10 14:54:09 +00:00
case Visibility::Private:
case Visibility::Internal:
return nullptr;
2019-12-10 14:54:09 +00:00
case Visibility::Public:
case Visibility::External:
return TypeProvider::function(*this);
2017-01-10 15:26:13 +00:00
}
// To make the compiler happy
return nullptr;
2017-01-10 15:26:13 +00:00
}
2015-09-21 16:55:58 +00:00
VariableDeclarationAnnotation& VariableDeclaration::annotation() const
{
return initAnnotation<VariableDeclarationAnnotation>();
2015-09-21 16:55:58 +00:00
}
2015-10-26 16:20:29 +00:00
StatementAnnotation& Statement::annotation() const
{
return initAnnotation<StatementAnnotation>();
2015-10-26 16:20:29 +00:00
}
InlineAssemblyAnnotation& InlineAssembly::annotation() const
{
return initAnnotation<InlineAssemblyAnnotation>();
}
2019-12-20 01:20:27 +00:00
BlockAnnotation& Block::annotation() const
{
return initAnnotation<BlockAnnotation>();
2019-12-20 01:20:27 +00:00
}
TryCatchClauseAnnotation& TryCatchClause::annotation() const
{
return initAnnotation<TryCatchClauseAnnotation>();
2019-12-20 01:20:27 +00:00
}
ForStatementAnnotation& ForStatement::annotation() const
{
return initAnnotation<ForStatementAnnotation>();
2019-12-20 01:20:27 +00:00
}
2015-09-21 16:55:58 +00:00
ReturnAnnotation& Return::annotation() const
{
return initAnnotation<ReturnAnnotation>();
2015-09-21 16:55:58 +00:00
}
ExpressionAnnotation& Expression::annotation() const
{
return initAnnotation<ExpressionAnnotation>();
2015-09-21 16:55:58 +00:00
}
MemberAccessAnnotation& MemberAccess::annotation() const
{
return initAnnotation<MemberAccessAnnotation>();
2015-09-21 16:55:58 +00:00
}
BinaryOperationAnnotation& BinaryOperation::annotation() const
{
return initAnnotation<BinaryOperationAnnotation>();
2015-09-21 16:55:58 +00:00
}
FunctionCallAnnotation& FunctionCall::annotation() const
{
return initAnnotation<FunctionCallAnnotation>();
2015-09-21 16:55:58 +00:00
}
IdentifierAnnotation& Identifier::annotation() const
{
return initAnnotation<IdentifierAnnotation>();
2015-09-21 16:55:58 +00:00
}
ASTString Literal::valueWithoutUnderscores() const
{
return boost::erase_all_copy(value(), "_");
}
2017-06-28 15:59:34 +00:00
bool Literal::isHexNumber() const
2017-06-26 11:49:05 +00:00
{
if (token() != Token::Number)
return false;
2017-06-28 16:00:14 +00:00
return boost::starts_with(value(), "0x");
2017-06-26 11:49:05 +00:00
}
bool Literal::looksLikeAddress() const
{
if (subDenomination() != SubDenomination::None)
return false;
2017-06-26 11:49:05 +00:00
2017-06-28 15:59:34 +00:00
if (!isHexNumber())
2017-06-22 14:39:42 +00:00
return false;
return abs(int(valueWithoutUnderscores().length()) - 42) <= 1;
}
bool Literal::passesAddressChecksum() const
{
2017-06-28 15:59:34 +00:00
solAssert(isHexNumber(), "Expected hex number");
2019-12-11 16:31:36 +00:00
return util::passesAddressChecksum(valueWithoutUnderscores(), true);
}
2018-08-07 13:58:34 +00:00
string Literal::getChecksummedAddress() const
{
solAssert(isHexNumber(), "Expected hex number");
/// Pad literal to be a proper hex address.
string address = valueWithoutUnderscores().substr(2);
if (address.length() > 40)
return string();
address.insert(address.begin(), 40 - address.size(), '0');
2019-12-11 16:31:36 +00:00
return util::getChecksummedAddress(address);
}
TryCatchClause const* TryStatement::successClause() const
{
solAssert(m_clauses.size() > 0, "");
return m_clauses[0].get();
}
TryCatchClause const* TryStatement::structuredClause() const
{
for (size_t i = 1; i < m_clauses.size(); ++i)
if (m_clauses[i]->errorName() == "Error")
return m_clauses[i].get();
return nullptr;
}
TryCatchClause const* TryStatement::fallbackClause() const
{
for (size_t i = 1; i < m_clauses.size(); ++i)
if (m_clauses[i]->errorName().empty())
return m_clauses[i].get();
return nullptr;
}