001///////////////////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code and other text files for adherence to a set of rules.
003// Copyright (C) 2001-2025 the original author or authors.
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018///////////////////////////////////////////////////////////////////////////////////////////////
019
020package com.puppycrawl.tools.checkstyle.grammar;
021
022import java.io.Serial;
023import java.util.Objects;
024
025import org.antlr.v4.runtime.CommonToken;
026import org.antlr.v4.runtime.Token;
027
028/**
029 * A simple wrapper for ANTLR {@link Token} that provides a proper {@link #equals(Object)}
030 * and {@link #hashCode()} implementation based on the token's {@code type} and {@code text}.
031 *
032 * <p>This is useful because ANTLR's default {@code CommonToken} does not override
033 * {@code equals}, It compares references.
034 */
035public final class SimpleToken extends CommonToken {
036
037    @Serial
038    private static final long serialVersionUID = 1L;
039
040    /**
041     * Constructs a new instance from an existing ANTLR {@link Token}.
042     *
043     * @param token the ANTLR token to wrap
044     */
045    private SimpleToken(
046            Token token) {
047        super(token);
048        setTokenIndex(token.getTokenIndex());
049    }
050
051    /**
052     * Creates a new instance from an existing ANTLR {@link Token}.
053     *
054     * @param token the ANTLR token to wrap
055     * @return a new instance of SimpleToken wrapping the provided token
056     */
057    public static SimpleToken from(Token token) {
058        return new SimpleToken(token);
059    }
060
061    @Override
062    public boolean equals(Object obj) {
063        if (this == obj) {
064            return true;
065        }
066        if (obj == null) {
067            return false;
068        }
069        if (getClass() != obj.getClass()) {
070            return false;
071        }
072        final SimpleToken other = (SimpleToken) obj;
073        return getType() == other.getType()
074                && getText().equals(other.getText())
075                && getLine() == other.getLine()
076                && getTokenIndex() == other.getTokenIndex()
077                && getCharPositionInLine() == other.getCharPositionInLine()
078                && getStartIndex() == other.getStartIndex()
079                && getStopIndex() == other.getStopIndex();
080    }
081
082    @Override
083    public int hashCode() {
084        return Objects.hash(
085                getType(),
086                getText(),
087                getLine(),
088                getTokenIndex(),
089                getCharPositionInLine(),
090                getStartIndex(),
091                getStopIndex()
092        );
093    }
094}