Pull to refresh

Comments 58

Если кто-то не знает, что такое цикломатическая сложность 1000, то пусть и не знает. Психическое здоровье будет лучше :). В общем, много это.

Воодушевленно прочел первую часть предложения, но… пошел в Википедию.
Блин, из-за напутствия не удалось стать первым, кто задал вопрос «Сообщили ли о найденных ошибках?» :D

Поэтому задам другой вопрос — сколько для хромиума вам пришлось раз менять исходный код, чтобы задавить «левые» ошибки?
И почему нельзя постфактум задавить ошибку от макроса?
Вы имеете ввиду код хромиума или код анализатора?
«Можно подавить эти предупреждения, вписав в заголовочный файл, рядом с объявлением макроса, вот такой вот комментарий:
//-V:DVLOG:501»
то есть, таки в код хромиума.

хотя после вопроса мне стало интересно — а в коде анализатора что-либо правилось, по результату прогона про хромиуму?
Да, правилось. Что к чему именно относится, долго смотреть. Но суммарно по результатам проверок проектов Chromium и MTASA были внесены улучшения в следующие диагностики: V502, V512, V517, V519, V521, V523, V531, V536, V542, V550, V584, V595, V620, V634, V656, V620, V653, V654, V659, V661, V669, V670.
Ого. А теперь представим, что я купил анализатор, прогнал проект, получил тонну мусора.
Мне надо писать вам, дабы вы улучшили анализатор, или всё давить со своей стороны и жить с тем, что есть?
То есть если бы ответ выше был «ничего не улучшали в анализаторе, даже и не думали», то это был бы «правильный» ответ? :-). Всегда работая с проектами мы стараемся улучшать анализатор. «Стыдиться» нам здесь совершенно нечего.

По сути вопроса 1. Да, пользователь может много подавить самостоятельно и в этом и заключается в том числе работа с инструментом. 2. Да, многие пользователи нам пишут предложения по сокращению ложных срабатываний и мы их реализуем.
То есть таки по сути вопроса: «нет, не надо, но да, можно». Спасибо :)
На каждый конкретный вид ложного срабатывания надо смотреть отдельно. Что-то из очевидного, Вы скорее всего подавите сами. Про остальное можно написать. Мы отберем явные ляпы анализа или то, что может быть полезно другим. Это мы реализуем в виде правок в коде. По остальным моментам дадим рекомендации. Иногда, мы делаем для пользователей специальные настройки, которые другим не нужны. Например, пользователь вписывает себе волшебный комментарий //Сделать_мне_хорошо_с_диагностикой_Vxx и что-то работает немного по другому для его проектов.
> И почему нельзя постфактум задавить ошибку от макроса?

Мы иногда вносим правки/исключения в правила, после проверки очередного проекта. Но не всегда конечно. Это помощь одному конкретному проекту. Не универсально слишком. Только код анализатора пухнет. Мы стараемся делать правки, если хотя бы теоретически, это может помочь и другим проектам.

Конкретно с макросом DVLOG ничего делать не стал. Имя короткое и вполне возможно не уникальное (или в другом месте, это будет часть какого-то слова, например, FindVLogin). В другом проекте это может значить совсем другое и мы можем пропустить полезную диагностику.
Под «постфактум» я имел ввиду как раз интерактивный обзор лога.
Открылось 3к ошибок.
Смотрю на 1ю, 2ю, 3ю, понимаю, что все они — от одного макроса; правой кнопкой => Ignore all macros DVLOG errors => профит, остались только остальные ошибки.

Не вписывая "//-V:DVLOG:501" а просто постфактум, уже собрав всю информацию, выключить его — можно?
А в предыдущем треде утверждали, что надо менять исходники и перекомпиливать.
Так надо или нет?
Если говорить о механизме с использованием комментариев, то нужен перезапуск. Не путать с подавлением одиночных сообщений //-Vxxx — здесь не нужен :-).

А есть другой грубый механизм. Он убирает сообщения, где встретилась определенная фраза. Он доступен через настройки и перезапуск не нужен. Евгений видимо его имел в виду. Но для случая с DVLOG он бы не подошел.

А вообще, как то урывками объяснения получаются. :) Лучше сразу целиком прочитать "Подавление ложных предупреждений".
Да я уже понял, что с макросами у вас объективно не очень, так как вы обрабатываете код после макросов, где информации о макросах просто не осталось.
Причем и посоветовать-то нечего. Правильный выход — разбирать и строить дерево самостоятельно — слишком накладно по расходам на разработку и поддержку в случае обновлений.

Ну и основная претензия на «Перезапустим анализ; мы получим на одно сообщение меньше» — если даёте интерактивный инструмент, в идеале, все сделанные вот такие (инструментом) правки должны вступать в силу немедленно. И удалять все false alarm'ы тут же и сразу. А этого явно нет.
Медалька с перечеркиванием смотрится неоднозначно. Лучше сделать довольного единорога без радуги.
У нас есть идея профессионально перерисовать такую медальку. Но как-то руки всё не доходят. :)
Так был же вроде вот этот персонаж:

image

Почему бы и нет? Довольный и окрыленный от радости :)
Какое-то у него неправильное количество рук-ног
Какой вы требовательный =)
Да что там — однозначно плохо смотрится.
Перечеркивание — негатив, блюющий носорог — еще один.
И они не перемножаются, они складываются.
Замечательный инструмент! У меня только один вопрос: а когда и кто это исправит в chromium?
Хотите помочь сообществу и заработать денег? Вчера стартовал очередной этап проекта "Платим за ошибки в Chromium" от Google. Сообщите им об этих ошибках и кто знает, может повезет…
Не так уж страшна эта ваша цикломатическая сложность 1106
bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
{
    // If we have a token in progress, then we're supposed to be called back
    // with the same token so we can finish it.
    ASSERT(!m_token || m_token == &token || token.type() == HTMLToken::Uninitialized);
    m_token = &token;

    if (!m_bufferedEndTagName.isEmpty() && !isEndTagBufferingState(m_state)) {
        // FIXME: This should call flushBufferedEndTag().
        // We started an end tag during our last iteration.
        m_token->beginEndTag(m_bufferedEndTagName);
        m_bufferedEndTagName.clear();
        m_appropriateEndTagName.clear();
        m_temporaryBuffer.clear();
        if (m_state == HTMLTokenizer::DataState) {
            // We're back in the data state, so we must be done with the tag.
            return true;
        }
    }

    if (source.isEmpty() || !m_inputStreamPreprocessor.peek(source))
        return haveBufferedCharacterToken();
    UChar cc = m_inputStreamPreprocessor.nextInputCharacter();

    // Source: http://www.whatwg.org/specs/web-apps/current-work/#tokenisation0
    switch (m_state) {
    HTML_BEGIN_STATE(DataState) {
        if (cc == '&')
            HTML_ADVANCE_TO(CharacterReferenceInDataState);
        else if (cc == '<') {
            if (m_token->type() == HTMLToken::Character) {
                // We have a bunch of character tokens queued up that we
                // are emitting lazily here.
                return true;
            }
            HTML_ADVANCE_TO(TagOpenState);
        } else if (cc == kEndOfFileMarker)
            return emitEndOfFile(source);
        else {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(DataState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(CharacterReferenceInDataState) {
        if (!processEntity(source))
            return haveBufferedCharacterToken();
        HTML_SWITCH_TO(DataState);
    }
    END_STATE()

    HTML_BEGIN_STATE(RCDATAState) {
        if (cc == '&')
            HTML_ADVANCE_TO(CharacterReferenceInRCDATAState);
        else if (cc == '<')
            HTML_ADVANCE_TO(RCDATALessThanSignState);
        else if (cc == kEndOfFileMarker)
            return emitEndOfFile(source);
        else {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(RCDATAState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(CharacterReferenceInRCDATAState) {
        if (!processEntity(source))
            return haveBufferedCharacterToken();
        HTML_SWITCH_TO(RCDATAState);
    }
    END_STATE()

    HTML_BEGIN_STATE(RAWTEXTState) {
        if (cc == '<')
            HTML_ADVANCE_TO(RAWTEXTLessThanSignState);
        else if (cc == kEndOfFileMarker)
            return emitEndOfFile(source);
        else {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(RAWTEXTState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataState) {
        if (cc == '<')
            HTML_ADVANCE_TO(ScriptDataLessThanSignState);
        else if (cc == kEndOfFileMarker)
            return emitEndOfFile(source);
        else {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(PLAINTEXTState) {
        if (cc == kEndOfFileMarker)
            return emitEndOfFile(source);
        bufferCharacter(cc);
        HTML_ADVANCE_TO(PLAINTEXTState);
    }
    END_STATE()

    HTML_BEGIN_STATE(TagOpenState) {
        if (cc == '!')
            HTML_ADVANCE_TO(MarkupDeclarationOpenState);
        else if (cc == '/')
            HTML_ADVANCE_TO(EndTagOpenState);
        else if (isASCIIUpper(cc)) {
            m_token->beginStartTag(toLowerCase(cc));
            HTML_ADVANCE_TO(TagNameState);
        } else if (isASCIILower(cc)) {
            m_token->beginStartTag(cc);
            HTML_ADVANCE_TO(TagNameState);
        } else if (cc == '?') {
            parseError();
            // The spec consumes the current character before switching
            // to the bogus comment state, but it's easier to implement
            // if we reconsume the current character.
            HTML_RECONSUME_IN(BogusCommentState);
        } else {
            parseError();
            bufferCharacter('<');
            HTML_RECONSUME_IN(DataState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(EndTagOpenState) {
        if (isASCIIUpper(cc)) {
            m_token->beginEndTag(static_cast<LChar>(toLowerCase(cc)));
            m_appropriateEndTagName.clear();
            HTML_ADVANCE_TO(TagNameState);
        } else if (isASCIILower(cc)) {
            m_token->beginEndTag(static_cast<LChar>(cc));
            m_appropriateEndTagName.clear();
            HTML_ADVANCE_TO(TagNameState);
        } else if (cc == '>') {
            parseError();
            HTML_ADVANCE_TO(DataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            bufferCharacter('<');
            bufferCharacter('/');
            HTML_RECONSUME_IN(DataState);
        } else {
            parseError();
            HTML_RECONSUME_IN(BogusCommentState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(TagNameState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(BeforeAttributeNameState);
        else if (cc == '/')
            HTML_ADVANCE_TO(SelfClosingStartTagState);
        else if (cc == '>')
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        else if (isASCIIUpper(cc)) {
            m_token->appendToName(toLowerCase(cc));
            HTML_ADVANCE_TO(TagNameState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            HTML_RECONSUME_IN(DataState);
        } else {
            m_token->appendToName(cc);
            HTML_ADVANCE_TO(TagNameState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(RCDATALessThanSignState) {
        if (cc == '/') {
            m_temporaryBuffer.clear();
            ASSERT(m_bufferedEndTagName.isEmpty());
            HTML_ADVANCE_TO(RCDATAEndTagOpenState);
        } else {
            bufferCharacter('<');
            HTML_RECONSUME_IN(RCDATAState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(RCDATAEndTagOpenState) {
        if (isASCIIUpper(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
            HTML_ADVANCE_TO(RCDATAEndTagNameState);
        } else if (isASCIILower(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(cc));
            HTML_ADVANCE_TO(RCDATAEndTagNameState);
        } else {
            bufferCharacter('<');
            bufferCharacter('/');
            HTML_RECONSUME_IN(RCDATAState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(RCDATAEndTagNameState) {
        if (isASCIIUpper(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
            HTML_ADVANCE_TO(RCDATAEndTagNameState);
        } else if (isASCIILower(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(cc));
            HTML_ADVANCE_TO(RCDATAEndTagNameState);
        } else {
            if (isTokenizerWhitespace(cc)) {
                if (isAppropriateEndTag()) {
                    m_temporaryBuffer.append(static_cast<LChar>(cc));
                    FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
                }
            } else if (cc == '/') {
                if (isAppropriateEndTag()) {
                    m_temporaryBuffer.append(static_cast<LChar>(cc));
                    FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
                }
            } else if (cc == '>') {
                if (isAppropriateEndTag()) {
                    m_temporaryBuffer.append(static_cast<LChar>(cc));
                    return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
                }
            }
            bufferCharacter('<');
            bufferCharacter('/');
            m_token->appendToCharacter(m_temporaryBuffer);
            m_bufferedEndTagName.clear();
            m_temporaryBuffer.clear();
            HTML_RECONSUME_IN(RCDATAState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(RAWTEXTLessThanSignState) {
        if (cc == '/') {
            m_temporaryBuffer.clear();
            ASSERT(m_bufferedEndTagName.isEmpty());
            HTML_ADVANCE_TO(RAWTEXTEndTagOpenState);
        } else {
            bufferCharacter('<');
            HTML_RECONSUME_IN(RAWTEXTState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(RAWTEXTEndTagOpenState) {
        if (isASCIIUpper(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
            HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
        } else if (isASCIILower(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(cc));
            HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
        } else {
            bufferCharacter('<');
            bufferCharacter('/');
            HTML_RECONSUME_IN(RAWTEXTState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(RAWTEXTEndTagNameState) {
        if (isASCIIUpper(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
            HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
        } else if (isASCIILower(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(cc));
            HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
        } else {
            if (isTokenizerWhitespace(cc)) {
                if (isAppropriateEndTag()) {
                    m_temporaryBuffer.append(static_cast<LChar>(cc));
                    FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
                }
            } else if (cc == '/') {
                if (isAppropriateEndTag()) {
                    m_temporaryBuffer.append(static_cast<LChar>(cc));
                    FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
                }
            } else if (cc == '>') {
                if (isAppropriateEndTag()) {
                    m_temporaryBuffer.append(static_cast<LChar>(cc));
                    return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
                }
            }
            bufferCharacter('<');
            bufferCharacter('/');
            m_token->appendToCharacter(m_temporaryBuffer);
            m_bufferedEndTagName.clear();
            m_temporaryBuffer.clear();
            HTML_RECONSUME_IN(RAWTEXTState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataLessThanSignState) {
        if (cc == '/') {
            m_temporaryBuffer.clear();
            ASSERT(m_bufferedEndTagName.isEmpty());
            HTML_ADVANCE_TO(ScriptDataEndTagOpenState);
        } else if (cc == '!') {
            bufferCharacter('<');
            bufferCharacter('!');
            HTML_ADVANCE_TO(ScriptDataEscapeStartState);
        } else {
            bufferCharacter('<');
            HTML_RECONSUME_IN(ScriptDataState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataEndTagOpenState) {
        if (isASCIIUpper(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
            HTML_ADVANCE_TO(ScriptDataEndTagNameState);
        } else if (isASCIILower(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(cc));
            HTML_ADVANCE_TO(ScriptDataEndTagNameState);
        } else {
            bufferCharacter('<');
            bufferCharacter('/');
            HTML_RECONSUME_IN(ScriptDataState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataEndTagNameState) {
        if (isASCIIUpper(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
            HTML_ADVANCE_TO(ScriptDataEndTagNameState);
        } else if (isASCIILower(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(cc));
            HTML_ADVANCE_TO(ScriptDataEndTagNameState);
        } else {
            if (isTokenizerWhitespace(cc)) {
                if (isAppropriateEndTag()) {
                    m_temporaryBuffer.append(static_cast<LChar>(cc));
                    FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
                }
            } else if (cc == '/') {
                if (isAppropriateEndTag()) {
                    m_temporaryBuffer.append(static_cast<LChar>(cc));
                    FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
                }
            } else if (cc == '>') {
                if (isAppropriateEndTag()) {
                    m_temporaryBuffer.append(static_cast<LChar>(cc));
                    return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
                }
            }
            bufferCharacter('<');
            bufferCharacter('/');
            m_token->appendToCharacter(m_temporaryBuffer);
            m_bufferedEndTagName.clear();
            m_temporaryBuffer.clear();
            HTML_RECONSUME_IN(ScriptDataState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataEscapeStartState) {
        if (cc == '-') {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataEscapeStartDashState);
        } else
            HTML_RECONSUME_IN(ScriptDataState);
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataEscapeStartDashState) {
        if (cc == '-') {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataEscapedDashDashState);
        } else
            HTML_RECONSUME_IN(ScriptDataState);
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataEscapedState) {
        if (cc == '-') {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataEscapedDashState);
        } else if (cc == '<')
            HTML_ADVANCE_TO(ScriptDataEscapedLessThanSignState);
        else if (cc == kEndOfFileMarker) {
            parseError();
            HTML_RECONSUME_IN(DataState);
        } else {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataEscapedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataEscapedDashState) {
        if (cc == '-') {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataEscapedDashDashState);
        } else if (cc == '<')
            HTML_ADVANCE_TO(ScriptDataEscapedLessThanSignState);
        else if (cc == kEndOfFileMarker) {
            parseError();
            HTML_RECONSUME_IN(DataState);
        } else {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataEscapedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataEscapedDashDashState) {
        if (cc == '-') {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataEscapedDashDashState);
        } else if (cc == '<')
            HTML_ADVANCE_TO(ScriptDataEscapedLessThanSignState);
        else if (cc == '>') {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            HTML_RECONSUME_IN(DataState);
        } else {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataEscapedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataEscapedLessThanSignState) {
        if (cc == '/') {
            m_temporaryBuffer.clear();
            ASSERT(m_bufferedEndTagName.isEmpty());
            HTML_ADVANCE_TO(ScriptDataEscapedEndTagOpenState);
        } else if (isASCIIUpper(cc)) {
            bufferCharacter('<');
            bufferCharacter(cc);
            m_temporaryBuffer.clear();
            m_temporaryBuffer.append(toLowerCase(cc));
            HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
        } else if (isASCIILower(cc)) {
            bufferCharacter('<');
            bufferCharacter(cc);
            m_temporaryBuffer.clear();
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
        } else {
            bufferCharacter('<');
            HTML_RECONSUME_IN(ScriptDataEscapedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataEscapedEndTagOpenState) {
        if (isASCIIUpper(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
            HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
        } else if (isASCIILower(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(cc));
            HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
        } else {
            bufferCharacter('<');
            bufferCharacter('/');
            HTML_RECONSUME_IN(ScriptDataEscapedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataEscapedEndTagNameState) {
        if (isASCIIUpper(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
            HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
        } else if (isASCIILower(cc)) {
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            addToPossibleEndTag(static_cast<LChar>(cc));
            HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
        } else {
            if (isTokenizerWhitespace(cc)) {
                if (isAppropriateEndTag()) {
                    m_temporaryBuffer.append(static_cast<LChar>(cc));
                    FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
                }
            } else if (cc == '/') {
                if (isAppropriateEndTag()) {
                    m_temporaryBuffer.append(static_cast<LChar>(cc));
                    FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
                }
            } else if (cc == '>') {
                if (isAppropriateEndTag()) {
                    m_temporaryBuffer.append(static_cast<LChar>(cc));
                    return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
                }
            }
            bufferCharacter('<');
            bufferCharacter('/');
            m_token->appendToCharacter(m_temporaryBuffer);
            m_bufferedEndTagName.clear();
            m_temporaryBuffer.clear();
            HTML_RECONSUME_IN(ScriptDataEscapedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataDoubleEscapeStartState) {
        if (isTokenizerWhitespace(cc) || cc == '/' || cc == '>') {
            bufferCharacter(cc);
            if (temporaryBufferIs(scriptTag.localName()))
                HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
            else
                HTML_ADVANCE_TO(ScriptDataEscapedState);
        } else if (isASCIIUpper(cc)) {
            bufferCharacter(cc);
            m_temporaryBuffer.append(toLowerCase(cc));
            HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
        } else if (isASCIILower(cc)) {
            bufferCharacter(cc);
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
        } else
            HTML_RECONSUME_IN(ScriptDataEscapedState);
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataDoubleEscapedState) {
        if (cc == '-') {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataDoubleEscapedDashState);
        } else if (cc == '<') {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataDoubleEscapedLessThanSignState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            HTML_RECONSUME_IN(DataState);
        } else {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataDoubleEscapedDashState) {
        if (cc == '-') {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataDoubleEscapedDashDashState);
        } else if (cc == '<') {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataDoubleEscapedLessThanSignState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            HTML_RECONSUME_IN(DataState);
        } else {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataDoubleEscapedDashDashState) {
        if (cc == '-') {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataDoubleEscapedDashDashState);
        } else if (cc == '<') {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataDoubleEscapedLessThanSignState);
        } else if (cc == '>') {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            HTML_RECONSUME_IN(DataState);
        } else {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataDoubleEscapedLessThanSignState) {
        if (cc == '/') {
            bufferCharacter(cc);
            m_temporaryBuffer.clear();
            HTML_ADVANCE_TO(ScriptDataDoubleEscapeEndState);
        } else
            HTML_RECONSUME_IN(ScriptDataDoubleEscapedState);
    }
    END_STATE()

    HTML_BEGIN_STATE(ScriptDataDoubleEscapeEndState) {
        if (isTokenizerWhitespace(cc) || cc == '/' || cc == '>') {
            bufferCharacter(cc);
            if (temporaryBufferIs(scriptTag.localName()))
                HTML_ADVANCE_TO(ScriptDataEscapedState);
            else
                HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
        } else if (isASCIIUpper(cc)) {
            bufferCharacter(cc);
            m_temporaryBuffer.append(toLowerCase(cc));
            HTML_ADVANCE_TO(ScriptDataDoubleEscapeEndState);
        } else if (isASCIILower(cc)) {
            bufferCharacter(cc);
            m_temporaryBuffer.append(static_cast<LChar>(cc));
            HTML_ADVANCE_TO(ScriptDataDoubleEscapeEndState);
        } else
            HTML_RECONSUME_IN(ScriptDataDoubleEscapedState);
    }
    END_STATE()

    HTML_BEGIN_STATE(BeforeAttributeNameState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(BeforeAttributeNameState);
        else if (cc == '/')
            HTML_ADVANCE_TO(SelfClosingStartTagState);
        else if (cc == '>')
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        else if (isASCIIUpper(cc)) {
            m_token->addNewAttribute();
            m_token->beginAttributeName(source.numberOfCharactersConsumed());
            m_token->appendToAttributeName(toLowerCase(cc));
            HTML_ADVANCE_TO(AttributeNameState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            HTML_RECONSUME_IN(DataState);
        } else {
            if (cc == '"' || cc == '\'' || cc == '<' || cc == '=')
                parseError();
            m_token->addNewAttribute();
            m_token->beginAttributeName(source.numberOfCharactersConsumed());
            m_token->appendToAttributeName(cc);
            HTML_ADVANCE_TO(AttributeNameState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(AttributeNameState) {
        if (isTokenizerWhitespace(cc)) {
            m_token->endAttributeName(source.numberOfCharactersConsumed());
            HTML_ADVANCE_TO(AfterAttributeNameState);
        } else if (cc == '/') {
            m_token->endAttributeName(source.numberOfCharactersConsumed());
            HTML_ADVANCE_TO(SelfClosingStartTagState);
        } else if (cc == '=') {
            m_token->endAttributeName(source.numberOfCharactersConsumed());
            HTML_ADVANCE_TO(BeforeAttributeValueState);
        } else if (cc == '>') {
            m_token->endAttributeName(source.numberOfCharactersConsumed());
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        } else if (isASCIIUpper(cc)) {
            m_token->appendToAttributeName(toLowerCase(cc));
            HTML_ADVANCE_TO(AttributeNameState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->endAttributeName(source.numberOfCharactersConsumed());
            HTML_RECONSUME_IN(DataState);
        } else {
            if (cc == '"' || cc == '\'' || cc == '<' || cc == '=')
                parseError();
            m_token->appendToAttributeName(cc);
            HTML_ADVANCE_TO(AttributeNameState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(AfterAttributeNameState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(AfterAttributeNameState);
        else if (cc == '/')
            HTML_ADVANCE_TO(SelfClosingStartTagState);
        else if (cc == '=')
            HTML_ADVANCE_TO(BeforeAttributeValueState);
        else if (cc == '>')
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        else if (isASCIIUpper(cc)) {
            m_token->addNewAttribute();
            m_token->beginAttributeName(source.numberOfCharactersConsumed());
            m_token->appendToAttributeName(toLowerCase(cc));
            HTML_ADVANCE_TO(AttributeNameState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            HTML_RECONSUME_IN(DataState);
        } else {
            if (cc == '"' || cc == '\'' || cc == '<')
                parseError();
            m_token->addNewAttribute();
            m_token->beginAttributeName(source.numberOfCharactersConsumed());
            m_token->appendToAttributeName(cc);
            HTML_ADVANCE_TO(AttributeNameState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(BeforeAttributeValueState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(BeforeAttributeValueState);
        else if (cc == '"') {
            m_token->beginAttributeValue(source.numberOfCharactersConsumed() + 1);
            HTML_ADVANCE_TO(AttributeValueDoubleQuotedState);
        } else if (cc == '&') {
            m_token->beginAttributeValue(source.numberOfCharactersConsumed());
            HTML_RECONSUME_IN(AttributeValueUnquotedState);
        } else if (cc == '\'') {
            m_token->beginAttributeValue(source.numberOfCharactersConsumed() + 1);
            HTML_ADVANCE_TO(AttributeValueSingleQuotedState);
        } else if (cc == '>') {
            parseError();
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            HTML_RECONSUME_IN(DataState);
        } else {
            if (cc == '<' || cc == '=' || cc == '`')
                parseError();
            m_token->beginAttributeValue(source.numberOfCharactersConsumed());
            m_token->appendToAttributeValue(cc);
            HTML_ADVANCE_TO(AttributeValueUnquotedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(AttributeValueDoubleQuotedState) {
        if (cc == '"') {
            m_token->endAttributeValue(source.numberOfCharactersConsumed());
            HTML_ADVANCE_TO(AfterAttributeValueQuotedState);
        } else if (cc == '&') {
            m_additionalAllowedCharacter = '"';
            HTML_ADVANCE_TO(CharacterReferenceInAttributeValueState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->endAttributeValue(source.numberOfCharactersConsumed());
            HTML_RECONSUME_IN(DataState);
        } else {
            m_token->appendToAttributeValue(cc);
            HTML_ADVANCE_TO(AttributeValueDoubleQuotedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(AttributeValueSingleQuotedState) {
        if (cc == '\'') {
            m_token->endAttributeValue(source.numberOfCharactersConsumed());
            HTML_ADVANCE_TO(AfterAttributeValueQuotedState);
        } else if (cc == '&') {
            m_additionalAllowedCharacter = '\'';
            HTML_ADVANCE_TO(CharacterReferenceInAttributeValueState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->endAttributeValue(source.numberOfCharactersConsumed());
            HTML_RECONSUME_IN(DataState);
        } else {
            m_token->appendToAttributeValue(cc);
            HTML_ADVANCE_TO(AttributeValueSingleQuotedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(AttributeValueUnquotedState) {
        if (isTokenizerWhitespace(cc)) {
            m_token->endAttributeValue(source.numberOfCharactersConsumed());
            HTML_ADVANCE_TO(BeforeAttributeNameState);
        } else if (cc == '&') {
            m_additionalAllowedCharacter = '>';
            HTML_ADVANCE_TO(CharacterReferenceInAttributeValueState);
        } else if (cc == '>') {
            m_token->endAttributeValue(source.numberOfCharactersConsumed());
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->endAttributeValue(source.numberOfCharactersConsumed());
            HTML_RECONSUME_IN(DataState);
        } else {
            if (cc == '"' || cc == '\'' || cc == '<' || cc == '=' || cc == '`')
                parseError();
            m_token->appendToAttributeValue(cc);
            HTML_ADVANCE_TO(AttributeValueUnquotedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(CharacterReferenceInAttributeValueState) {
        bool notEnoughCharacters = false;
        DecodedHTMLEntity decodedEntity;
        bool success = consumeHTMLEntity(source, decodedEntity, notEnoughCharacters, m_additionalAllowedCharacter);
        if (notEnoughCharacters)
            return haveBufferedCharacterToken();
        if (!success) {
            ASSERT(decodedEntity.isEmpty());
            m_token->appendToAttributeValue('&');
        } else {
            for (unsigned i = 0; i < decodedEntity.length; ++i)
                m_token->appendToAttributeValue(decodedEntity.data[i]);
        }
        // We're supposed to switch back to the attribute value state that
        // we were in when we were switched into this state. Rather than
        // keeping track of this explictly, we observe that the previous
        // state can be determined by m_additionalAllowedCharacter.
        if (m_additionalAllowedCharacter == '"')
            HTML_SWITCH_TO(AttributeValueDoubleQuotedState);
        else if (m_additionalAllowedCharacter == '\'')
            HTML_SWITCH_TO(AttributeValueSingleQuotedState);
        else if (m_additionalAllowedCharacter == '>')
            HTML_SWITCH_TO(AttributeValueUnquotedState);
        else
            ASSERT_NOT_REACHED();
    }
    END_STATE()

    HTML_BEGIN_STATE(AfterAttributeValueQuotedState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(BeforeAttributeNameState);
        else if (cc == '/')
            HTML_ADVANCE_TO(SelfClosingStartTagState);
        else if (cc == '>')
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        else if (cc == kEndOfFileMarker) {
            parseError();
            HTML_RECONSUME_IN(DataState);
        } else {
            parseError();
            HTML_RECONSUME_IN(BeforeAttributeNameState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(SelfClosingStartTagState) {
        if (cc == '>') {
            m_token->setSelfClosing();
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            HTML_RECONSUME_IN(DataState);
        } else {
            parseError();
            HTML_RECONSUME_IN(BeforeAttributeNameState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(BogusCommentState) {
        m_token->beginComment();
        HTML_RECONSUME_IN(ContinueBogusCommentState);
    }
    END_STATE()

    HTML_BEGIN_STATE(ContinueBogusCommentState) {
        if (cc == '>')
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        else if (cc == kEndOfFileMarker)
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        else {
            m_token->appendToComment(cc);
            HTML_ADVANCE_TO(ContinueBogusCommentState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(MarkupDeclarationOpenState) {
        DEFINE_STATIC_LOCAL(String, dashDashString, ("--"));
        DEFINE_STATIC_LOCAL(String, doctypeString, ("doctype"));
        DEFINE_STATIC_LOCAL(String, cdataString, ("[CDATA["));
        if (cc == '-') {
            SegmentedString::LookAheadResult result = source.lookAhead(dashDashString);
            if (result == SegmentedString::DidMatch) {
                source.advanceAndASSERT('-');
                source.advanceAndASSERT('-');
                m_token->beginComment();
                HTML_SWITCH_TO(CommentStartState);
            } else if (result == SegmentedString::NotEnoughCharacters)
                return haveBufferedCharacterToken();
        } else if (cc == 'D' || cc == 'd') {
            SegmentedString::LookAheadResult result = source.lookAheadIgnoringCase(doctypeString);
            if (result == SegmentedString::DidMatch) {
                advanceStringAndASSERTIgnoringCase(source, "doctype");
                HTML_SWITCH_TO(DOCTYPEState);
            } else if (result == SegmentedString::NotEnoughCharacters)
                return haveBufferedCharacterToken();
        } else if (cc == '[' && shouldAllowCDATA()) {
            SegmentedString::LookAheadResult result = source.lookAhead(cdataString);
            if (result == SegmentedString::DidMatch) {
                advanceStringAndASSERT(source, "[CDATA[");
                HTML_SWITCH_TO(CDATASectionState);
            } else if (result == SegmentedString::NotEnoughCharacters)
                return haveBufferedCharacterToken();
        }
        parseError();
        HTML_RECONSUME_IN(BogusCommentState);
    }
    END_STATE()

    HTML_BEGIN_STATE(CommentStartState) {
        if (cc == '-')
            HTML_ADVANCE_TO(CommentStartDashState);
        else if (cc == '>') {
            parseError();
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            m_token->appendToComment(cc);
            HTML_ADVANCE_TO(CommentState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(CommentStartDashState) {
        if (cc == '-')
            HTML_ADVANCE_TO(CommentEndState);
        else if (cc == '>') {
            parseError();
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            m_token->appendToComment('-');
            m_token->appendToComment(cc);
            HTML_ADVANCE_TO(CommentState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(CommentState) {
        if (cc == '-')
            HTML_ADVANCE_TO(CommentEndDashState);
        else if (cc == kEndOfFileMarker) {
            parseError();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            m_token->appendToComment(cc);
            HTML_ADVANCE_TO(CommentState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(CommentEndDashState) {
        if (cc == '-')
            HTML_ADVANCE_TO(CommentEndState);
        else if (cc == kEndOfFileMarker) {
            parseError();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            m_token->appendToComment('-');
            m_token->appendToComment(cc);
            HTML_ADVANCE_TO(CommentState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(CommentEndState) {
        if (cc == '>')
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        else if (cc == '!') {
            parseError();
            HTML_ADVANCE_TO(CommentEndBangState);
        } else if (cc == '-') {
            parseError();
            m_token->appendToComment('-');
            HTML_ADVANCE_TO(CommentEndState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            parseError();
            m_token->appendToComment('-');
            m_token->appendToComment('-');
            m_token->appendToComment(cc);
            HTML_ADVANCE_TO(CommentState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(CommentEndBangState) {
        if (cc == '-') {
            m_token->appendToComment('-');
            m_token->appendToComment('-');
            m_token->appendToComment('!');
            HTML_ADVANCE_TO(CommentEndDashState);
        } else if (cc == '>')
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        else if (cc == kEndOfFileMarker) {
            parseError();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            m_token->appendToComment('-');
            m_token->appendToComment('-');
            m_token->appendToComment('!');
            m_token->appendToComment(cc);
            HTML_ADVANCE_TO(CommentState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(DOCTYPEState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(BeforeDOCTYPENameState);
        else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->beginDOCTYPE();
            m_token->setForceQuirks();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            parseError();
            HTML_RECONSUME_IN(BeforeDOCTYPENameState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(BeforeDOCTYPENameState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(BeforeDOCTYPENameState);
        else if (isASCIIUpper(cc)) {
            m_token->beginDOCTYPE(toLowerCase(cc));
            HTML_ADVANCE_TO(DOCTYPENameState);
        } else if (cc == '>') {
            parseError();
            m_token->beginDOCTYPE();
            m_token->setForceQuirks();
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->beginDOCTYPE();
            m_token->setForceQuirks();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            m_token->beginDOCTYPE(cc);
            HTML_ADVANCE_TO(DOCTYPENameState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(DOCTYPENameState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(AfterDOCTYPENameState);
        else if (cc == '>')
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        else if (isASCIIUpper(cc)) {
            m_token->appendToName(toLowerCase(cc));
            HTML_ADVANCE_TO(DOCTYPENameState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->setForceQuirks();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            m_token->appendToName(cc);
            HTML_ADVANCE_TO(DOCTYPENameState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(AfterDOCTYPENameState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(AfterDOCTYPENameState);
        if (cc == '>')
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->setForceQuirks();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            DEFINE_STATIC_LOCAL(String, publicString, ("public"));
            DEFINE_STATIC_LOCAL(String, systemString, ("system"));
            if (cc == 'P' || cc == 'p') {
                SegmentedString::LookAheadResult result = source.lookAheadIgnoringCase(publicString);
                if (result == SegmentedString::DidMatch) {
                    advanceStringAndASSERTIgnoringCase(source, "public");
                    HTML_SWITCH_TO(AfterDOCTYPEPublicKeywordState);
                } else if (result == SegmentedString::NotEnoughCharacters)
                    return haveBufferedCharacterToken();
            } else if (cc == 'S' || cc == 's') {
                SegmentedString::LookAheadResult result = source.lookAheadIgnoringCase(systemString);
                if (result == SegmentedString::DidMatch) {
                    advanceStringAndASSERTIgnoringCase(source, "system");
                    HTML_SWITCH_TO(AfterDOCTYPESystemKeywordState);
                } else if (result == SegmentedString::NotEnoughCharacters)
                    return haveBufferedCharacterToken();
            }
            parseError();
            m_token->setForceQuirks();
            HTML_ADVANCE_TO(BogusDOCTYPEState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(AfterDOCTYPEPublicKeywordState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(BeforeDOCTYPEPublicIdentifierState);
        else if (cc == '"') {
            parseError();
            m_token->setPublicIdentifierToEmptyString();
            HTML_ADVANCE_TO(DOCTYPEPublicIdentifierDoubleQuotedState);
        } else if (cc == '\'') {
            parseError();
            m_token->setPublicIdentifierToEmptyString();
            HTML_ADVANCE_TO(DOCTYPEPublicIdentifierSingleQuotedState);
        } else if (cc == '>') {
            parseError();
            m_token->setForceQuirks();
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->setForceQuirks();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            parseError();
            m_token->setForceQuirks();
            HTML_ADVANCE_TO(BogusDOCTYPEState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(BeforeDOCTYPEPublicIdentifierState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(BeforeDOCTYPEPublicIdentifierState);
        else if (cc == '"') {
            m_token->setPublicIdentifierToEmptyString();
            HTML_ADVANCE_TO(DOCTYPEPublicIdentifierDoubleQuotedState);
        } else if (cc == '\'') {
            m_token->setPublicIdentifierToEmptyString();
            HTML_ADVANCE_TO(DOCTYPEPublicIdentifierSingleQuotedState);
        } else if (cc == '>') {
            parseError();
            m_token->setForceQuirks();
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->setForceQuirks();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            parseError();
            m_token->setForceQuirks();
            HTML_ADVANCE_TO(BogusDOCTYPEState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(DOCTYPEPublicIdentifierDoubleQuotedState) {
        if (cc == '"')
            HTML_ADVANCE_TO(AfterDOCTYPEPublicIdentifierState);
        else if (cc == '>') {
            parseError();
            m_token->setForceQuirks();
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->setForceQuirks();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            m_token->appendToPublicIdentifier(cc);
            HTML_ADVANCE_TO(DOCTYPEPublicIdentifierDoubleQuotedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(DOCTYPEPublicIdentifierSingleQuotedState) {
        if (cc == '\'')
            HTML_ADVANCE_TO(AfterDOCTYPEPublicIdentifierState);
        else if (cc == '>') {
            parseError();
            m_token->setForceQuirks();
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->setForceQuirks();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            m_token->appendToPublicIdentifier(cc);
            HTML_ADVANCE_TO(DOCTYPEPublicIdentifierSingleQuotedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(AfterDOCTYPEPublicIdentifierState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(BetweenDOCTYPEPublicAndSystemIdentifiersState);
        else if (cc == '>')
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        else if (cc == '"') {
            parseError();
            m_token->setSystemIdentifierToEmptyString();
            HTML_ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
        } else if (cc == '\'') {
            parseError();
            m_token->setSystemIdentifierToEmptyString();
            HTML_ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->setForceQuirks();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            parseError();
            m_token->setForceQuirks();
            HTML_ADVANCE_TO(BogusDOCTYPEState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(BetweenDOCTYPEPublicAndSystemIdentifiersState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(BetweenDOCTYPEPublicAndSystemIdentifiersState);
        else if (cc == '>')
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        else if (cc == '"') {
            m_token->setSystemIdentifierToEmptyString();
            HTML_ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
        } else if (cc == '\'') {
            m_token->setSystemIdentifierToEmptyString();
            HTML_ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->setForceQuirks();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            parseError();
            m_token->setForceQuirks();
            HTML_ADVANCE_TO(BogusDOCTYPEState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(AfterDOCTYPESystemKeywordState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(BeforeDOCTYPESystemIdentifierState);
        else if (cc == '"') {
            parseError();
            m_token->setSystemIdentifierToEmptyString();
            HTML_ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
        } else if (cc == '\'') {
            parseError();
            m_token->setSystemIdentifierToEmptyString();
            HTML_ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
        } else if (cc == '>') {
            parseError();
            m_token->setForceQuirks();
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->setForceQuirks();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            parseError();
            m_token->setForceQuirks();
            HTML_ADVANCE_TO(BogusDOCTYPEState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(BeforeDOCTYPESystemIdentifierState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(BeforeDOCTYPESystemIdentifierState);
        if (cc == '"') {
            m_token->setSystemIdentifierToEmptyString();
            HTML_ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
        } else if (cc == '\'') {
            m_token->setSystemIdentifierToEmptyString();
            HTML_ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
        } else if (cc == '>') {
            parseError();
            m_token->setForceQuirks();
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->setForceQuirks();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            parseError();
            m_token->setForceQuirks();
            HTML_ADVANCE_TO(BogusDOCTYPEState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(DOCTYPESystemIdentifierDoubleQuotedState) {
        if (cc == '"')
            HTML_ADVANCE_TO(AfterDOCTYPESystemIdentifierState);
        else if (cc == '>') {
            parseError();
            m_token->setForceQuirks();
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->setForceQuirks();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            m_token->appendToSystemIdentifier(cc);
            HTML_ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(DOCTYPESystemIdentifierSingleQuotedState) {
        if (cc == '\'')
            HTML_ADVANCE_TO(AfterDOCTYPESystemIdentifierState);
        else if (cc == '>') {
            parseError();
            m_token->setForceQuirks();
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        } else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->setForceQuirks();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            m_token->appendToSystemIdentifier(cc);
            HTML_ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(AfterDOCTYPESystemIdentifierState) {
        if (isTokenizerWhitespace(cc))
            HTML_ADVANCE_TO(AfterDOCTYPESystemIdentifierState);
        else if (cc == '>')
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        else if (cc == kEndOfFileMarker) {
            parseError();
            m_token->setForceQuirks();
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        } else {
            parseError();
            HTML_ADVANCE_TO(BogusDOCTYPEState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(BogusDOCTYPEState) {
        if (cc == '>')
            return emitAndResumeIn(source, HTMLTokenizer::DataState);
        else if (cc == kEndOfFileMarker)
            return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
        HTML_ADVANCE_TO(BogusDOCTYPEState);
    }
    END_STATE()

    HTML_BEGIN_STATE(CDATASectionState) {
        if (cc == ']')
            HTML_ADVANCE_TO(CDATASectionRightSquareBracketState);
        else if (cc == kEndOfFileMarker)
            HTML_RECONSUME_IN(DataState);
        else {
            bufferCharacter(cc);
            HTML_ADVANCE_TO(CDATASectionState);
        }
    }
    END_STATE()

    HTML_BEGIN_STATE(CDATASectionRightSquareBracketState) {
        if (cc == ']')
            HTML_ADVANCE_TO(CDATASectionDoubleRightSquareBracketState);
        else {
            bufferCharacter(']');
            HTML_RECONSUME_IN(CDATASectionState);
        }
    }

    HTML_BEGIN_STATE(CDATASectionDoubleRightSquareBracketState) {
        if (cc == '>')
            HTML_ADVANCE_TO(DataState);
        else {
            bufferCharacter(']');
            bufferCharacter(']');
            HTML_RECONSUME_IN(CDATASectionState);
        }
    }
    END_STATE()

    }

    ASSERT_NOT_REACHED();
    return false;
}

Согласен. В общем, просто много if. С циклами и goto можно понаписать намного запутанней. Однако, чем было, тем и мерил.
А сложность мерялась до или после разворачивания макросов?
Налицо ошибка расчета. Так как погромист работает ДО макросов. И это выглядит как простые вызовы функторов.
В описании цикломатической сложности, кажется ничего не говорится про макросы. Потом, не считать тоже плохо. А то попрячут всё в макросы. :)
А чем макрос отличается от функции? Только тем, что он функтор, фактически же.
То, что система функций на сях настолько гиблая, что функторы получаемы только макросами — это уже второй вопрос :)
С точки зрения программиста — они являются одной единицей.
Совершенно очевидно, что «не налицо». Считать сложный макрос за «единичку» при расчете цикломатической сложности несправедливо.
1 макрос = 1 функция. их цели эквивалентны — упрятать повторяющуюся часть кода в маленький отдельный кусочек
// ADPCM codecs

#define DK3_GET_NEXT_NIBBLE() \
    if (decode_top_nibble_next) \
    { \
        nibble = (last_byte >> 4) & 0x0F; \
        decode_top_nibble_next = 0; \
    } \
    else \
    { \
        last_byte = *src++; \
        if (src >= buf + buf_size) break; \
        nibble = last_byte & 0x0F; \
        decode_top_nibble_next = 1; \
    }


Да, да… Особенно, мило break; смотрится. :)
Пожалуйста, эквивалент на функциях:
def proceed():
  ....
  def DK3_GET_NEXT_NIBBLE():
    if decode_top_nibble_next:
      nibble = (last_byte>>4) & 0x0F
    else:
      last_byte = buf[srci]
      srci += 1
      if srci >= buf_size:
        raise BufferOverrun()
      nibble = last_byte & 0x0F
    decode_top_nibble_next ^= True

  try:
    while True:
      ...
      DK3_GET_NEXT_NIBBLE()
  except BufferOverrun():
     pass # its ok, just end of loop
>Замеченное N8 — «одноразовые» циклы

Одноразовые циклы могут быть удобным инструментом, когда в конце функции нужно выполнить какую-то очистку, но по ходу самой функции есть много мест, когда нужно прервать работу и перейти к этой очистке. В итоге имеем выбор:

-Заводить кучу флагов
-Бросать\ловить исключения
-Использовать goto
-Написать код вида
do { ... } while(false); 
//тут очистка

и переходить к очистке простым break.

Последний способ выглядит элегантнее предыдущих. RAII, конечно, ещё элегантнее, но иногда ради него нужно наворотить лишних 20-30 строк и это портит ощущение красоты кода.
Согласен. Но такие места я и не выписываю. То что я выписал, очень не похоже на предложенные варианты. :)
Я бы всё же предпочел исключения, а если по каким-то причинам это неприемлемо, то банальный goto — это как раз тот случай когда его применение оправдано, особенно в случае повышенных требований к быстродействию.

Еще популярный и элегантный вариант — оформление в виде отдельной функции тела «цикла» с несколькими return. Собственно его и использую чаще всего. А при оптимизации компилятором он вполне может заинлайниться и не отличаться от кода с goto в итоге ничем.
Использовать исключения для штатной передачи управления — последняя глупость, какую только можно представить. Очень большие накладные расходы.
А вот блок finally как раз для этого придуман.
Смотря что считать штатной, а что нет. В простом CRUD приложении выходит до десятка нештатных, когда до штатного выполнения запроса дело не доходит, это ошибки конфигурирования и формирования среды. А штатная — получение пустого результата на запрос.

А разве блок finally в C++ работает не совместно исключительно с исключениями? А в используемой мною версии основного языка блоков finally пока нет.
UFO just landed and posted this here
>>V547 Expression 'socket_ < 0' is always false. Unsigned type value is never < 0. tcp_server_socket_win.cc 48

А компилятор разве не должен в данном случае матернуться?
Некоторые могут. Если специально попросить. Просто по умолчанию такое обычно выключено. В мире столько кода с подобными проверками… Анализатору PVS-Studio приходится прикладывать много усилий, чтобы попытаться отличить ошибку от нормального кода. И всё равно много ложных срабатываний. Понапишут, понатопчат… :)
Ну, строго говоря, код у самого Микрософта не блещет правильностью (да и остальные тоже не святые) — я после догого времени написания кода на С под *никсы пересел на шарп — так меня бесят _знаковые_ параметры для смещения в тех же функциях работы с отображаемой памятью. Но раз исторически так сложилось…
Исторически сложилось, что беззнаковые типы не были включены в Common Language Specification, поэтому не могут использоваться в CLS-совместимых сборках.
Два раза происходит сравнение со строкой «text». Это подозрительно. Возможно, одна строка просто лишняя. А может быть, отсутствует другое нужное здесь сравнение.

Похоже, там должен быть color.
«This issue was found by a Linter.» — редко же они его запускают! :D
Получается, что не только неудавшийся ТОП1, но три следующих функции являются реализациями КА парсеров, и наврняка целиком или частично сформированы автоматом. Сомневаюсь, что та же HTMLTokenizer::nextToken написана вручную.

К чему я. Лучше бы примеры функций из другой области взять.
И да, мерить стоит до разворачивания макросов. Т.е. тот код, с которым работает разработчик, а не компилятор.
Самая максимальная цикломатическая сложность, равная 2782, принадлежит функции ValidateChunkAMD64() в проекте Chromium. Но её пришлось дисквалифицировать из состязания. Функция находится в файле validator_x86_64.c, который является автогенерируемым. Жаль. А то был бы эпичный рекордсмен. Я и близко с такой цикломатической сложностью не сталкивался.

Это ещё не самая сложная её версия. Промежуточные версии, насколько я знаю, в trunk так и не попали, так как требовали 10+ минут на компиляцию… или просто сносили крышу компилятору и он крэшился :)
Я видел ф-цию с цикломатической сложностью в 315. Я узнал, что у МСВЦ есть ограничение на вложенность блоков. Я думал, что я видел ВСЕ. Оказалось, что бывает и похуже…
> Замеченное N2 — противоположные условия

if (*i == '"') {
    while (i != header_value.end() && *i != '"') ++i;
  ....


а разве условия здесь противоположные?
Попробуйте подобрать значение символа, на который указывает 'i', чтобы выполнилось ++i.
а разве это не тоже самое?

if ($header_value[0] != '"') {
     while (($i != strlen($header_value)) && ($header_value[$i] != '"')) $i++;
     ...
Предлагаю внимательно перечитать пример. :)
> [...] Но её пришлось дисквалифицировать из состязания. Функция находится в файле [...], который является автогенерируемым.
> [...]
> 2. Библиотека Mesa. Функция _mesa_glsl_lex() в файле glsl_lexer.cc. Цикломатическая сложность 1088.


Это тоже сгенерировано (lex).
Sign up to leave a comment.