/* 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 . */ #include #include #include namespace solidity::tools { /** * Helper that provides functions which analyze certain source locations * on a textual base. They utilize regular expression to search for * keywords or to determine formatting. */ class SourceAnalysis { public: static bool isMultilineKeyword( langutil::SourceLocation const& _location, std::string const& _keyword ) { return regex_search( _location.text(), std::regex{"(\\b" + _keyword + "\\b\\n|\\r|\\r\\n)"} ); } static bool hasMutabilityKeyword(langutil::SourceLocation const& _location) { return regex_search( _location.text(), std::regex{"(\\b(pure|view|nonpayable|payable)\\b)"} ); } static bool hasVirtualKeyword(langutil::SourceLocation const& _location) { return regex_search(_location.text(), std::regex{"(\\b(virtual)\\b)"}); } static bool hasVisibilityKeyword(langutil::SourceLocation const& _location) { return regex_search(_location.text(), std::regex{"\\bpublic\\b"}); } }; /** * Helper that provides functions which can analyse declarations and * generate source snippets based on the information retrieved. */ class SourceGeneration { public: using CompareFunction = frontend::OverrideChecker::CompareByID; using Contracts = std::set; /// Generates an `override` declaration for single overrides /// or `override(...)` with contract list for multiple overrides. static std::string functionOverride(Contracts const& _contracts) { if (_contracts.size() <= 1) return "override"; std::string overrideList; for (auto inheritedContract: _contracts) overrideList += inheritedContract->name() + ","; return "override(" + overrideList.substr(0, overrideList.size() - 1) + ")"; } }; /** * Helper that provides functions which apply changes to Solidity source code * on a textual base. In general, these utilize regular expressions applied * to the given source location. */ class SourceTransform { public: /// Searches for the keyword given and prepends the expression. /// E.g. `function f() view;` -> `function f() public view;` static std::string insertBeforeKeyword( langutil::SourceLocation const& _location, std::string const& _keyword, std::string const& _expression ) { return regex_replace( _location.text(), std::regex{"(\\b" + _keyword + "\\b)"}, _expression + " " + _keyword ); } /// Searches for the keyword given and appends the expression. /// E.g. `function f() public {}` -> `function f() public override {}` static std::string insertAfterKeyword( langutil::SourceLocation const& _location, std::string const& _keyword, std::string const& _expression ) { bool isMultiline = SourceAnalysis::isMultilineKeyword(_location, _keyword); std::string toAppend = isMultiline ? ("\n " + _expression) : (" " + _expression); std::regex keyword{"(\\b" + _keyword + "\\b)"}; return regex_replace(_location.text(), keyword, _keyword + toAppend); } /// Searches for the first right parenthesis and appends the expression /// given. /// E.g. `function f() {}` -> `function f() public {}` static std::string insertAfterRightParenthesis( langutil::SourceLocation const& _location, std::string const& _expression ) { return regex_replace( _location.text(), std::regex{"(\\))"}, ") " + _expression ); } /// Searches for the `function` keyword and its identifier and replaces /// both by the expression given. /// E.g. `function Storage() {}` -> `constructor() {}` static std::string replaceFunctionName( langutil::SourceLocation const& _location, std::string const& _name, std::string const& _expression ) { return regex_replace( _location.text(), std::regex{"(\\bfunction\\s*" + _name + "\\b)"}, _expression ); } }; }