mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Use all referenced errors.
This commit is contained in:
parent
1057fd5355
commit
e877e2bba7
@ -30,6 +30,8 @@ set(sources
|
|||||||
analysis/OverrideChecker.h
|
analysis/OverrideChecker.h
|
||||||
analysis/PostTypeChecker.cpp
|
analysis/PostTypeChecker.cpp
|
||||||
analysis/PostTypeChecker.h
|
analysis/PostTypeChecker.h
|
||||||
|
analysis/PostTypeContractLevelChecker.cpp
|
||||||
|
analysis/PostTypeContractLevelChecker.h
|
||||||
analysis/ReferencesResolver.cpp
|
analysis/ReferencesResolver.cpp
|
||||||
analysis/ReferencesResolver.h
|
analysis/ReferencesResolver.h
|
||||||
analysis/Scoper.cpp
|
analysis/Scoper.cpp
|
||||||
|
@ -433,24 +433,6 @@ void ContractLevelChecker::checkHashCollisions(ContractDefinition const& _contra
|
|||||||
);
|
);
|
||||||
hashes.insert(hash);
|
hashes.insert(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
map<uint32_t, SourceLocation> errorHashes;
|
|
||||||
for (ErrorDefinition const* error: _contract.interfaceErrors())
|
|
||||||
{
|
|
||||||
if (!error->functionType(true)->interfaceFunctionType())
|
|
||||||
// This will result in an error later on, so we can ignore it here.
|
|
||||||
continue;
|
|
||||||
uint32_t hash = selectorFromSignature32(error->functionType(true)->externalSignature());
|
|
||||||
if (errorHashes.count(hash))
|
|
||||||
m_errorReporter.typeError(
|
|
||||||
4883_error,
|
|
||||||
_contract.location(),
|
|
||||||
SecondarySourceLocation{}.append("This error has the same selector: "s, errorHashes[hash]),
|
|
||||||
"Error signature hash collision for " + error->functionType(true)->externalSignature()
|
|
||||||
);
|
|
||||||
else
|
|
||||||
errorHashes[hash] = error->location();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContractLevelChecker::checkLibraryRequirements(ContractDefinition const& _contract)
|
void ContractLevelChecker::checkLibraryRequirements(ContractDefinition const& _contract)
|
||||||
|
@ -125,6 +125,8 @@ bool FunctionCallGraphBuilder::visit(FunctionCall const& _functionCall)
|
|||||||
// change at runtime). All we can do is to add an edge to the dispatch which in turn has
|
// change at runtime). All we can do is to add an edge to the dispatch which in turn has
|
||||||
// edges to all functions could possibly be called.
|
// edges to all functions could possibly be called.
|
||||||
add(m_currentNode, CallGraph::SpecialNode::InternalDispatch);
|
add(m_currentNode, CallGraph::SpecialNode::InternalDispatch);
|
||||||
|
else if (functionType->kind() == FunctionType::Kind::Error)
|
||||||
|
m_graph.usedErrors.insert(&dynamic_cast<ErrorDefinition const&>(functionType->declaration()));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -65,8 +65,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
FunctionCallGraphBuilder(ContractDefinition const& _contract):
|
FunctionCallGraphBuilder(ContractDefinition const& _contract):
|
||||||
m_contract(_contract),
|
m_contract(_contract)
|
||||||
m_graph{{}, {}, {}} {}
|
{}
|
||||||
|
|
||||||
bool visit(FunctionCall const& _functionCall) override;
|
bool visit(FunctionCall const& _functionCall) override;
|
||||||
bool visit(EmitStatement const& _emitStatement) override;
|
bool visit(EmitStatement const& _emitStatement) override;
|
||||||
|
72
libsolidity/analysis/PostTypeContractLevelChecker.cpp
Normal file
72
libsolidity/analysis/PostTypeContractLevelChecker.cpp
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
/**
|
||||||
|
* Component that verifies overloads, abstract contracts, function clashes and others
|
||||||
|
* checks at contract or function level.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libsolidity/analysis/PostTypeContractLevelChecker.h>
|
||||||
|
|
||||||
|
#include <libsolidity/ast/AST.h>
|
||||||
|
#include <libsolutil/FunctionSelector.h>
|
||||||
|
#include <liblangutil/ErrorReporter.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace solidity;
|
||||||
|
using namespace solidity::langutil;
|
||||||
|
using namespace solidity::frontend;
|
||||||
|
|
||||||
|
bool PostTypeContractLevelChecker::check(SourceUnit const& _sourceUnit)
|
||||||
|
{
|
||||||
|
bool noErrors = true;
|
||||||
|
for (auto* contract: ASTNode::filteredNodes<ContractDefinition>(_sourceUnit.nodes()))
|
||||||
|
if (!check(*contract))
|
||||||
|
noErrors = false;
|
||||||
|
return noErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PostTypeContractLevelChecker::check(ContractDefinition const& _contract)
|
||||||
|
{
|
||||||
|
solAssert(
|
||||||
|
_contract.annotation().creationCallGraph.set() &&
|
||||||
|
_contract.annotation().deployedCallGraph.set(),
|
||||||
|
""
|
||||||
|
);
|
||||||
|
|
||||||
|
map<uint32_t, map<string, SourceLocation>> errorHashes;
|
||||||
|
for (ErrorDefinition const* error: _contract.interfaceErrors())
|
||||||
|
{
|
||||||
|
string signature = error->functionType(true)->externalSignature();
|
||||||
|
uint32_t hash = selectorFromSignature32(signature);
|
||||||
|
// Fail if there is a different signature for the same hash.
|
||||||
|
if (!errorHashes[hash].empty() && !errorHashes[hash].count(signature))
|
||||||
|
{
|
||||||
|
SourceLocation& otherLocation = errorHashes[hash].begin()->second;
|
||||||
|
m_errorReporter.typeError(
|
||||||
|
4883_error,
|
||||||
|
error->nameLocation(),
|
||||||
|
SecondarySourceLocation{}.append("This error has a different signature but the same hash: ", otherLocation),
|
||||||
|
"Error signature hash collision for " + error->functionType(true)->externalSignature()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
errorHashes[hash][signature] = error->location();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Error::containsOnlyWarnings(m_errorReporter.errors());
|
||||||
|
}
|
56
libsolidity/analysis/PostTypeContractLevelChecker.h
Normal file
56
libsolidity/analysis/PostTypeContractLevelChecker.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
This file is part of solidity.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
/**
|
||||||
|
* Component that verifies properties at contract level, after the type checker has run.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <libsolidity/ast/ASTForward.h>
|
||||||
|
|
||||||
|
namespace solidity::langutil
|
||||||
|
{
|
||||||
|
class ErrorReporter;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace solidity::frontend
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component that verifies properties at contract level, after the type checker has run.
|
||||||
|
*/
|
||||||
|
class PostTypeContractLevelChecker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PostTypeContractLevelChecker(langutil::ErrorReporter& _errorReporter):
|
||||||
|
m_errorReporter(_errorReporter)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// Performs checks on the given source ast.
|
||||||
|
/// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
|
||||||
|
bool check(SourceUnit const& _sourceUnit);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Performs checks on the given contract.
|
||||||
|
/// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
|
||||||
|
bool check(ContractDefinition const& _contract);
|
||||||
|
|
||||||
|
langutil::ErrorReporter& m_errorReporter;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
|
|
||||||
|
#include <libsolidity/ast/CallGraph.h>
|
||||||
#include <libsolidity/ast/ASTVisitor.h>
|
#include <libsolidity/ast/ASTVisitor.h>
|
||||||
#include <libsolidity/ast/AST_accept.h>
|
#include <libsolidity/ast/AST_accept.h>
|
||||||
#include <libsolidity/ast/TypeProvider.h>
|
#include <libsolidity/ast/TypeProvider.h>
|
||||||
@ -174,12 +175,19 @@ vector<EventDefinition const*> const& ContractDefinition::interfaceEvents() cons
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<ErrorDefinition const*> ContractDefinition::interfaceErrors() const
|
vector<ErrorDefinition const*> ContractDefinition::interfaceErrors(bool _requireCallGraph) const
|
||||||
{
|
{
|
||||||
set<ErrorDefinition const*, CompareByID> result;
|
set<ErrorDefinition const*, CompareByID> result;
|
||||||
// TODO add all referenced errors
|
|
||||||
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
|
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
|
||||||
result += filteredNodes<ErrorDefinition>(contract->m_subNodes);
|
result += filteredNodes<ErrorDefinition>(contract->m_subNodes);
|
||||||
|
solAssert(annotation().creationCallGraph.set() == annotation().deployedCallGraph.set(), "");
|
||||||
|
if (_requireCallGraph)
|
||||||
|
solAssert(annotation().creationCallGraph.set(), "");
|
||||||
|
if (annotation().creationCallGraph.set())
|
||||||
|
{
|
||||||
|
result += (*annotation().creationCallGraph)->usedErrors;
|
||||||
|
result += (*annotation().deployedCallGraph)->usedErrors;
|
||||||
|
}
|
||||||
return convertContainer<vector<ErrorDefinition const*>>(move(result));
|
return convertContainer<vector<ErrorDefinition const*>>(move(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,7 +515,8 @@ public:
|
|||||||
std::vector<EventDefinition const*> const& interfaceEvents() const;
|
std::vector<EventDefinition const*> const& interfaceEvents() const;
|
||||||
/// @returns all errors defined in this contract or any base contract
|
/// @returns all errors defined in this contract or any base contract
|
||||||
/// and all errors referenced during execution.
|
/// and all errors referenced during execution.
|
||||||
std::vector<ErrorDefinition const*> interfaceErrors() const;
|
/// @param _requireCallGraph if false, do not fail if the call graph has not been computed yet.
|
||||||
|
std::vector<ErrorDefinition const*> interfaceErrors(bool _requireCallGraph = true) const;
|
||||||
bool isInterface() const { return m_contractKind == ContractKind::Interface; }
|
bool isInterface() const { return m_contractKind == ContractKind::Interface; }
|
||||||
bool isLibrary() const { return m_contractKind == ContractKind::Library; }
|
bool isLibrary() const { return m_contractKind == ContractKind::Library; }
|
||||||
|
|
||||||
|
@ -67,6 +67,9 @@ struct CallGraph
|
|||||||
|
|
||||||
/// Events that may get emitted by functions present in the graph.
|
/// Events that may get emitted by functions present in the graph.
|
||||||
std::set<EventDefinition const*, ASTNode::CompareByID> emittedEvents;
|
std::set<EventDefinition const*, ASTNode::CompareByID> emittedEvents;
|
||||||
|
|
||||||
|
/// Errors that are used by functions present in the graph.
|
||||||
|
std::set<ErrorDefinition const*, ASTNode::CompareByID> usedErrors;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include <libsolidity/analysis/GlobalContext.h>
|
#include <libsolidity/analysis/GlobalContext.h>
|
||||||
#include <libsolidity/analysis/NameAndTypeResolver.h>
|
#include <libsolidity/analysis/NameAndTypeResolver.h>
|
||||||
#include <libsolidity/analysis/PostTypeChecker.h>
|
#include <libsolidity/analysis/PostTypeChecker.h>
|
||||||
|
#include <libsolidity/analysis/PostTypeContractLevelChecker.h>
|
||||||
#include <libsolidity/analysis/StaticAnalyzer.h>
|
#include <libsolidity/analysis/StaticAnalyzer.h>
|
||||||
#include <libsolidity/analysis/SyntaxChecker.h>
|
#include <libsolidity/analysis/SyntaxChecker.h>
|
||||||
#include <libsolidity/analysis/Scoper.h>
|
#include <libsolidity/analysis/Scoper.h>
|
||||||
@ -433,6 +434,11 @@ bool CompilerStack::analyze()
|
|||||||
noErrors = false;
|
noErrors = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (noErrors)
|
||||||
|
for (Source const* source: m_sourceOrder)
|
||||||
|
if (source->ast && !PostTypeContractLevelChecker{m_errorReporter}.check(*source->ast))
|
||||||
|
noErrors = false;
|
||||||
|
|
||||||
// Check that immutable variables are never read in c'tors and assigned
|
// Check that immutable variables are never read in c'tors and assigned
|
||||||
// exactly once
|
// exactly once
|
||||||
if (noErrors)
|
if (noErrors)
|
||||||
|
@ -3,4 +3,4 @@ contract test {
|
|||||||
error tgeo();
|
error tgeo();
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// TypeError 4883: (0-52): Error signature hash collision for tgeo()
|
// TypeError 4883: (43-47): Error signature hash collision for tgeo()
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
library L {
|
||||||
|
error gsf();
|
||||||
|
}
|
||||||
|
contract test {
|
||||||
|
error tgeo();
|
||||||
|
function f(bool a) public {
|
||||||
|
if (a)
|
||||||
|
revert L.gsf();
|
||||||
|
else
|
||||||
|
revert tgeo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// TypeError 4883: (57-61): Error signature hash collision for tgeo()
|
Loading…
Reference in New Issue
Block a user