13af6ab5fSopenharmony_ci/**
23af6ab5fSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License.
53af6ab5fSopenharmony_ci * You may obtain a copy of the License at
63af6ab5fSopenharmony_ci *
73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
83af6ab5fSopenharmony_ci *
93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and
133af6ab5fSopenharmony_ci * limitations under the License.
143af6ab5fSopenharmony_ci */
153af6ab5fSopenharmony_ci
163af6ab5fSopenharmony_ci#include "ETSparser.h"
173af6ab5fSopenharmony_ci#include "ETSNolintParser.h"
183af6ab5fSopenharmony_ci
193af6ab5fSopenharmony_ci#include "lexer/lexer.h"
203af6ab5fSopenharmony_ci#include "ir/module/importNamespaceSpecifier.h"
213af6ab5fSopenharmony_ci
223af6ab5fSopenharmony_cinamespace ark::es2panda::parser {
233af6ab5fSopenharmony_ciETSNolintParser::ETSNolintParser(const ParserImpl *mainParser) : parser_(mainParser)
243af6ab5fSopenharmony_ci{
253af6ab5fSopenharmony_ci    line_ = parser_->Lexer()->Line();
263af6ab5fSopenharmony_ci
273af6ab5fSopenharmony_ci    warningsMap_ = {
283af6ab5fSopenharmony_ci        {std::u32string(U"ets-implicit-boxing-unboxing"), ETSWarnings::IMPLICIT_BOXING_UNBOXING},
293af6ab5fSopenharmony_ci        {std::u32string(U"ets-prohibit-top-level-statements"), ETSWarnings::PROHIBIT_TOP_LEVEL_STATEMENTS},
303af6ab5fSopenharmony_ci        {std::u32string(U"ets-boost-equality-statement"), ETSWarnings::BOOST_EQUALITY_STATEMENT},
313af6ab5fSopenharmony_ci        {std::u32string(U"ets-remove-lambda"), ETSWarnings::REMOVE_LAMBDA},
323af6ab5fSopenharmony_ci        {std::u32string(U"ets-suggest-final"), ETSWarnings::SUGGEST_FINAL},
333af6ab5fSopenharmony_ci        {std::u32string(U"ets-remove-async"), ETSWarnings::REMOVE_ASYNC_FUNCTIONS},
343af6ab5fSopenharmony_ci    };
353af6ab5fSopenharmony_ci}
363af6ab5fSopenharmony_ci
373af6ab5fSopenharmony_civoid ETSNolintParser::SetStartPos()
383af6ab5fSopenharmony_ci{
393af6ab5fSopenharmony_ci    line_ = parser_->Lexer()->Pos().Line();
403af6ab5fSopenharmony_ci    startPos_ = parser_->Lexer()->Pos().Iterator().Index();
413af6ab5fSopenharmony_ci    posOffset_ = startPos_;
423af6ab5fSopenharmony_ci
433af6ab5fSopenharmony_ci    BackwardSymbol(startPos_);
443af6ab5fSopenharmony_ci}
453af6ab5fSopenharmony_ci
463af6ab5fSopenharmony_civoid ETSNolintParser::CollectETSNolints()
473af6ab5fSopenharmony_ci{
483af6ab5fSopenharmony_ci    SetStartPos();
493af6ab5fSopenharmony_ci    char32_t cp = PeekSymbol();
503af6ab5fSopenharmony_ci
513af6ab5fSopenharmony_ci    while (cp != lexer::LEX_CHAR_EOS && cp != lexer::UNICODE_CODE_POINT_MAX && cp != lexer::UNICODE_INVALID_CP) {
523af6ab5fSopenharmony_ci        if (!IsEtsNolint()) {
533af6ab5fSopenharmony_ci            NextSymbol();
543af6ab5fSopenharmony_ci            cp = PeekSymbol();
553af6ab5fSopenharmony_ci            continue;
563af6ab5fSopenharmony_ci        }
573af6ab5fSopenharmony_ci        std::size_t line = line_;
583af6ab5fSopenharmony_ci        std::set<ETSWarnings> collection;
593af6ab5fSopenharmony_ci        if (IsNextLine()) {
603af6ab5fSopenharmony_ci            collection = ParseETSNolintArgs();
613af6ab5fSopenharmony_ci            line += 1;
623af6ab5fSopenharmony_ci        } else if (IsBegin()) {
633af6ab5fSopenharmony_ci            collection = ParseETSNolintArgs();
643af6ab5fSopenharmony_ci            for (const auto it : collection) {
653af6ab5fSopenharmony_ci                applyingCollection_.insert(it);
663af6ab5fSopenharmony_ci            }
673af6ab5fSopenharmony_ci        } else if (IsEnd()) {
683af6ab5fSopenharmony_ci            collection = ParseETSNolintArgs();
693af6ab5fSopenharmony_ci
703af6ab5fSopenharmony_ci            for (const auto it : collection) {
713af6ab5fSopenharmony_ci                applyingCollection_.erase(it);
723af6ab5fSopenharmony_ci            }
733af6ab5fSopenharmony_ci            cp = PeekSymbol();
743af6ab5fSopenharmony_ci            continue;
753af6ab5fSopenharmony_ci        } else {
763af6ab5fSopenharmony_ci            collection = ParseETSNolintArgs();
773af6ab5fSopenharmony_ci        }
783af6ab5fSopenharmony_ci        AddToETSNolintLinesCollection(line, collection);
793af6ab5fSopenharmony_ci        cp = PeekSymbol();
803af6ab5fSopenharmony_ci    }
813af6ab5fSopenharmony_ci
823af6ab5fSopenharmony_ci    RewindToStart();
833af6ab5fSopenharmony_ci}
843af6ab5fSopenharmony_ci
853af6ab5fSopenharmony_civoid ETSNolintParser::ApplyETSNolintsToStatements(ArenaVector<ir::Statement *> &statements) const
863af6ab5fSopenharmony_ci{
873af6ab5fSopenharmony_ci    for (auto *it : statements) {
883af6ab5fSopenharmony_ci        ApplyETSNolintsToNodesRecursively(it);
893af6ab5fSopenharmony_ci    }
903af6ab5fSopenharmony_ci}
913af6ab5fSopenharmony_ci
923af6ab5fSopenharmony_civoid ETSNolintParser::NextSymbol()
933af6ab5fSopenharmony_ci{
943af6ab5fSopenharmony_ci    if (PeekSymbol() == lexer::LEX_CHAR_LF) {
953af6ab5fSopenharmony_ci        if (!applyingCollection_.empty()) {
963af6ab5fSopenharmony_ci            AddToETSNolintLinesCollection(line_, applyingCollection_);
973af6ab5fSopenharmony_ci        }
983af6ab5fSopenharmony_ci        line_++;
993af6ab5fSopenharmony_ci    }
1003af6ab5fSopenharmony_ci
1013af6ab5fSopenharmony_ci    posOffset_++;
1023af6ab5fSopenharmony_ci    parser_->Lexer()->Pos().Iterator().Forward(1);
1033af6ab5fSopenharmony_ci}
1043af6ab5fSopenharmony_ci
1053af6ab5fSopenharmony_civoid ETSNolintParser::BackwardSymbol()
1063af6ab5fSopenharmony_ci{
1073af6ab5fSopenharmony_ci    posOffset_--;
1083af6ab5fSopenharmony_ci    parser_->Lexer()->Pos().Iterator().Backward(1);
1093af6ab5fSopenharmony_ci
1103af6ab5fSopenharmony_ci    if (PeekSymbol() == lexer::LEX_CHAR_LF) {
1113af6ab5fSopenharmony_ci        line_--;
1123af6ab5fSopenharmony_ci    }
1133af6ab5fSopenharmony_ci}
1143af6ab5fSopenharmony_ci
1153af6ab5fSopenharmony_civoid ETSNolintParser::NextSymbol(std::size_t i)
1163af6ab5fSopenharmony_ci{
1173af6ab5fSopenharmony_ci    for (; i > 0; --i) {
1183af6ab5fSopenharmony_ci        NextSymbol();
1193af6ab5fSopenharmony_ci    }
1203af6ab5fSopenharmony_ci}
1213af6ab5fSopenharmony_ci
1223af6ab5fSopenharmony_civoid ETSNolintParser::BackwardSymbol(std::size_t i)
1233af6ab5fSopenharmony_ci{
1243af6ab5fSopenharmony_ci    for (; i > 0; --i) {
1253af6ab5fSopenharmony_ci        BackwardSymbol();
1263af6ab5fSopenharmony_ci    }
1273af6ab5fSopenharmony_ci}
1283af6ab5fSopenharmony_ci
1293af6ab5fSopenharmony_civoid ETSNolintParser::RewindToStart() const
1303af6ab5fSopenharmony_ci{
1313af6ab5fSopenharmony_ci    parser_->Lexer()->Pos().Iterator().Backward(posOffset_ - startPos_);
1323af6ab5fSopenharmony_ci}
1333af6ab5fSopenharmony_ci
1343af6ab5fSopenharmony_civoid ETSNolintParser::AddToETSNolintLinesCollection(std::size_t line, const std::set<ETSWarnings> &collection)
1353af6ab5fSopenharmony_ci{
1363af6ab5fSopenharmony_ci    const auto search = linesCollection_.find(line);
1373af6ab5fSopenharmony_ci    if (search != linesCollection_.end()) {
1383af6ab5fSopenharmony_ci        search->second.insert(collection.begin(), collection.end());
1393af6ab5fSopenharmony_ci        return;
1403af6ab5fSopenharmony_ci    }
1413af6ab5fSopenharmony_ci
1423af6ab5fSopenharmony_ci    linesCollection_.insert({line, collection});
1433af6ab5fSopenharmony_ci}
1443af6ab5fSopenharmony_ci
1453af6ab5fSopenharmony_cichar32_t ETSNolintParser::PeekSymbol() const
1463af6ab5fSopenharmony_ci{
1473af6ab5fSopenharmony_ci    return parser_->Lexer()->Pos().Iterator().Peek();
1483af6ab5fSopenharmony_ci}
1493af6ab5fSopenharmony_ci
1503af6ab5fSopenharmony_cibool ETSNolintParser::TryPeekU32String(const std::u32string &u32str)
1513af6ab5fSopenharmony_ci{
1523af6ab5fSopenharmony_ci    std::size_t localPosOffset = 0;
1533af6ab5fSopenharmony_ci    char32_t cp;
1543af6ab5fSopenharmony_ci
1553af6ab5fSopenharmony_ci    for (const char32_t i : u32str) {
1563af6ab5fSopenharmony_ci        cp = PeekSymbol();
1573af6ab5fSopenharmony_ci        if (i != cp) {
1583af6ab5fSopenharmony_ci            BackwardSymbol(localPosOffset);
1593af6ab5fSopenharmony_ci            return false;
1603af6ab5fSopenharmony_ci        }
1613af6ab5fSopenharmony_ci        NextSymbol();
1623af6ab5fSopenharmony_ci        localPosOffset++;
1633af6ab5fSopenharmony_ci    }
1643af6ab5fSopenharmony_ci    return true;
1653af6ab5fSopenharmony_ci}
1663af6ab5fSopenharmony_ci
1673af6ab5fSopenharmony_cibool ETSNolintParser::IsEtsNolint()
1683af6ab5fSopenharmony_ci{
1693af6ab5fSopenharmony_ci    static const std::u32string ETSNOLINT_CHAR32T = {
1703af6ab5fSopenharmony_ci        lexer::LEX_CHAR_UPPERCASE_E, lexer::LEX_CHAR_UPPERCASE_T, lexer::LEX_CHAR_UPPERCASE_S,
1713af6ab5fSopenharmony_ci        lexer::LEX_CHAR_UPPERCASE_N, lexer::LEX_CHAR_UPPERCASE_O, lexer::LEX_CHAR_UPPERCASE_L,
1723af6ab5fSopenharmony_ci        lexer::LEX_CHAR_UPPERCASE_I, lexer::LEX_CHAR_UPPERCASE_N, lexer::LEX_CHAR_UPPERCASE_T};
1733af6ab5fSopenharmony_ci
1743af6ab5fSopenharmony_ci    char32_t cp;
1753af6ab5fSopenharmony_ci
1763af6ab5fSopenharmony_ci    for (unsigned long i = 0; i < ETSNOLINT_CHAR32T.length(); i++) {
1773af6ab5fSopenharmony_ci        cp = PeekSymbol();
1783af6ab5fSopenharmony_ci        if (ETSNOLINT_CHAR32T[i] != cp) {
1793af6ab5fSopenharmony_ci            return false;
1803af6ab5fSopenharmony_ci        }
1813af6ab5fSopenharmony_ci
1823af6ab5fSopenharmony_ci        NextSymbol();
1833af6ab5fSopenharmony_ci    }
1843af6ab5fSopenharmony_ci
1853af6ab5fSopenharmony_ci    return true;
1863af6ab5fSopenharmony_ci}
1873af6ab5fSopenharmony_ci
1883af6ab5fSopenharmony_cibool ETSNolintParser::IsNextLine()
1893af6ab5fSopenharmony_ci{
1903af6ab5fSopenharmony_ci    static const std::u32string NEXTLINE_CHAR32T = {
1913af6ab5fSopenharmony_ci        lexer::LEX_CHAR_MINUS,       lexer::LEX_CHAR_UPPERCASE_N, lexer::LEX_CHAR_UPPERCASE_E,
1923af6ab5fSopenharmony_ci        lexer::LEX_CHAR_UPPERCASE_X, lexer::LEX_CHAR_UPPERCASE_T, lexer::LEX_CHAR_UPPERCASE_L,
1933af6ab5fSopenharmony_ci        lexer::LEX_CHAR_UPPERCASE_I, lexer::LEX_CHAR_UPPERCASE_N, lexer::LEX_CHAR_UPPERCASE_E};
1943af6ab5fSopenharmony_ci
1953af6ab5fSopenharmony_ci    return TryPeekU32String(NEXTLINE_CHAR32T);
1963af6ab5fSopenharmony_ci}
1973af6ab5fSopenharmony_ci
1983af6ab5fSopenharmony_cibool ETSNolintParser::IsBegin()
1993af6ab5fSopenharmony_ci{
2003af6ab5fSopenharmony_ci    static const std::u32string BEGIN_CHAR32T = {lexer::LEX_CHAR_MINUS,       lexer::LEX_CHAR_UPPERCASE_B,
2013af6ab5fSopenharmony_ci                                                 lexer::LEX_CHAR_UPPERCASE_E, lexer::LEX_CHAR_UPPERCASE_G,
2023af6ab5fSopenharmony_ci                                                 lexer::LEX_CHAR_UPPERCASE_I, lexer::LEX_CHAR_UPPERCASE_N};
2033af6ab5fSopenharmony_ci
2043af6ab5fSopenharmony_ci    return TryPeekU32String(BEGIN_CHAR32T);
2053af6ab5fSopenharmony_ci}
2063af6ab5fSopenharmony_ci
2073af6ab5fSopenharmony_cibool ETSNolintParser::IsEnd()
2083af6ab5fSopenharmony_ci{
2093af6ab5fSopenharmony_ci    static const std::u32string END_CHAR32T = {lexer::LEX_CHAR_MINUS, lexer::LEX_CHAR_UPPERCASE_E,
2103af6ab5fSopenharmony_ci                                               lexer::LEX_CHAR_UPPERCASE_N, lexer::LEX_CHAR_UPPERCASE_D};
2113af6ab5fSopenharmony_ci
2123af6ab5fSopenharmony_ci    return TryPeekU32String(END_CHAR32T);
2133af6ab5fSopenharmony_ci}
2143af6ab5fSopenharmony_ci
2153af6ab5fSopenharmony_ciETSWarnings ETSNolintParser::MapETSNolintArg(const std::u32string &warningName) const
2163af6ab5fSopenharmony_ci{
2173af6ab5fSopenharmony_ci    const auto search = warningsMap_.find(warningName);
2183af6ab5fSopenharmony_ci    ASSERT(search != warningsMap_.end());
2193af6ab5fSopenharmony_ci
2203af6ab5fSopenharmony_ci    return search->second;
2213af6ab5fSopenharmony_ci}
2223af6ab5fSopenharmony_ci
2233af6ab5fSopenharmony_cibool ETSNolintParser::ValidETSNolintArg(const std::u32string &warningName) const
2243af6ab5fSopenharmony_ci{
2253af6ab5fSopenharmony_ci    return warningsMap_.find(warningName) != warningsMap_.end();
2263af6ab5fSopenharmony_ci}
2273af6ab5fSopenharmony_ci
2283af6ab5fSopenharmony_cistd::set<ETSWarnings> ETSNolintParser::ParseETSNolintArgs()
2293af6ab5fSopenharmony_ci{
2303af6ab5fSopenharmony_ci    std::set<ETSWarnings> warningsCollection;
2313af6ab5fSopenharmony_ci
2323af6ab5fSopenharmony_ci    if (PeekSymbol() != lexer::LEX_CHAR_LEFT_PAREN) {
2333af6ab5fSopenharmony_ci        for (const auto &it : warningsMap_) {
2343af6ab5fSopenharmony_ci            warningsCollection.insert(it.second);
2353af6ab5fSopenharmony_ci        }
2363af6ab5fSopenharmony_ci
2373af6ab5fSopenharmony_ci        return warningsCollection;
2383af6ab5fSopenharmony_ci    }
2393af6ab5fSopenharmony_ci
2403af6ab5fSopenharmony_ci    NextSymbol();
2413af6ab5fSopenharmony_ci    char32_t cp = 0;
2423af6ab5fSopenharmony_ci    std::u32string warningName;
2433af6ab5fSopenharmony_ci
2443af6ab5fSopenharmony_ci    while (cp != lexer::LEX_CHAR_SP && cp != lexer::LEX_CHAR_LF && cp != lexer::LEX_CHAR_EOS) {
2453af6ab5fSopenharmony_ci        cp = PeekSymbol();
2463af6ab5fSopenharmony_ci        if (cp != lexer::LEX_CHAR_MINUS && cp != lexer::LEX_CHAR_COMMA && cp != lexer::LEX_CHAR_RIGHT_PAREN &&
2473af6ab5fSopenharmony_ci            (cp < lexer::LEX_CHAR_LOWERCASE_A || cp > lexer::LEX_CHAR_LOWERCASE_Z)) {
2483af6ab5fSopenharmony_ci            const std::string msg = "Unexpected character for ETSNOLINT argument! [VALID ONLY: a-z, '-'].";
2493af6ab5fSopenharmony_ci            throw Error {ErrorType::SYNTAX, parser_->GetProgram()->SourceFilePath().Utf8(), msg.c_str(), line_ + 1, 0};
2503af6ab5fSopenharmony_ci        }
2513af6ab5fSopenharmony_ci        if ((cp == lexer::LEX_CHAR_COMMA || cp == lexer::LEX_CHAR_RIGHT_PAREN) && !ValidETSNolintArg(warningName)) {
2523af6ab5fSopenharmony_ci            const std::string msg = "Invalid argument for ETSNOLINT!";
2533af6ab5fSopenharmony_ci            throw Error {ErrorType::SYNTAX, parser_->GetProgram()->SourceFilePath().Utf8(), msg.c_str(), line_ + 1, 0};
2543af6ab5fSopenharmony_ci        }
2553af6ab5fSopenharmony_ci        if ((cp == lexer::LEX_CHAR_COMMA || cp == lexer::LEX_CHAR_RIGHT_PAREN) && ValidETSNolintArg(warningName)) {
2563af6ab5fSopenharmony_ci            warningsCollection.insert(MapETSNolintArg(warningName));
2573af6ab5fSopenharmony_ci            warningName.clear();
2583af6ab5fSopenharmony_ci        } else {
2593af6ab5fSopenharmony_ci            warningName += cp;
2603af6ab5fSopenharmony_ci        }
2613af6ab5fSopenharmony_ci        if (cp == lexer::LEX_CHAR_RIGHT_PAREN) {
2623af6ab5fSopenharmony_ci            break;
2633af6ab5fSopenharmony_ci        }
2643af6ab5fSopenharmony_ci
2653af6ab5fSopenharmony_ci        NextSymbol();
2663af6ab5fSopenharmony_ci    }
2673af6ab5fSopenharmony_ci
2683af6ab5fSopenharmony_ci    return warningsCollection;
2693af6ab5fSopenharmony_ci}
2703af6ab5fSopenharmony_ci
2713af6ab5fSopenharmony_cibool ETSNolintParser::IsLineWithETSNolint(const std::size_t line) const
2723af6ab5fSopenharmony_ci{
2733af6ab5fSopenharmony_ci    return linesCollection_.find(line) != linesCollection_.end();
2743af6ab5fSopenharmony_ci}
2753af6ab5fSopenharmony_ci
2763af6ab5fSopenharmony_cistd::set<ETSWarnings> ETSNolintParser::GetWarningsCollectionByLine(std::size_t line) const
2773af6ab5fSopenharmony_ci{
2783af6ab5fSopenharmony_ci    const auto search = linesCollection_.find(line);
2793af6ab5fSopenharmony_ci    return search == linesCollection_.end() ? std::set<ETSWarnings> {} : search->second;
2803af6ab5fSopenharmony_ci}
2813af6ab5fSopenharmony_ci
2823af6ab5fSopenharmony_civoid ETSNolintParser::ApplyETSNolintsToNodesRecursively(ir::AstNode *node) const
2833af6ab5fSopenharmony_ci{
2843af6ab5fSopenharmony_ci    if (node == nullptr) {
2853af6ab5fSopenharmony_ci        return;
2863af6ab5fSopenharmony_ci    }
2873af6ab5fSopenharmony_ci    const std::size_t line = node->Start().line;
2883af6ab5fSopenharmony_ci    if (IsLineWithETSNolint(line)) {
2893af6ab5fSopenharmony_ci        const std::set<ETSWarnings> warningsCollection = GetWarningsCollectionByLine(line);
2903af6ab5fSopenharmony_ci
2913af6ab5fSopenharmony_ci        parser_->GetProgram()->AddNodeToETSNolintCollection(node, warningsCollection);
2923af6ab5fSopenharmony_ci    }
2933af6ab5fSopenharmony_ci    node->Iterate([&](auto *childNode) { ApplyETSNolintsToNodesRecursively(childNode); });
2943af6ab5fSopenharmony_ci}
2953af6ab5fSopenharmony_ci}  // namespace ark::es2panda::parser
296