AliasesShouldBeUniqueListener.java

package org.thewonderlemming.c4plantuml.linter.rules.builtin;

import java.util.HashSet;
import java.util.Set;

import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.thewonderlemming.c4plantuml.commons.Reporter;
import org.thewonderlemming.c4plantuml.grammars.C4BaseListener;
import org.thewonderlemming.c4plantuml.grammars.SourceType;
import org.thewonderlemming.c4plantuml.grammars.generated.C4L1Parser;
import org.thewonderlemming.c4plantuml.grammars.generated.C4L2Parser;
import org.thewonderlemming.c4plantuml.grammars.generated.C4L3Parser;

/**
 * An ANTLR 4 {@link ParseTreeListener} implementation that verifies that aliases are not referring to more than one
 * entity (i.e. they are not declared more than once).
 *
 * @author thewonderlemming
 *
 */
public class AliasesShouldBeUniqueListener extends C4BaseListener {

    private final Set<String> aliases = new HashSet<>();

    private final Reporter reporter;

    private final AliasesShouldBeUniqueRule rule;


    /**
     * Default constructor.
     *
     * @param rule the {@link AliasesShouldBeUniqueRule} instance to refer to.
     * @param reporter {@link Reporter} instance to report to.
     */
    public AliasesShouldBeUniqueListener(final AliasesShouldBeUniqueRule rule, final Reporter reporter) {

        this.reporter = reporter;
        this.rule = rule;
    }

    /**
     * Collects the alias of a cloud definition in a {@link SourceType#C4_L1} grammar and verifies that it is not
     * already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterCloud(final C4L1Parser.CloudContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a cloud definition in a {@link SourceType#C4_L2} grammar and verifies that it is not
     * already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterCloud(final C4L2Parser.CloudContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a cloud definition in a {@link SourceType#C4_L3} grammar and verifies that it is not
     * already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterCloud(final C4L3Parser.CloudContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a component definition in a {@link SourceType#C4_L3} grammar and verifies that it is not
     * already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterComponent(final C4L3Parser.ComponentContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a container definition in a {@link SourceType#C4_L2} grammar and verifies that it is not
     * already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterContainer(final C4L2Parser.ContainerContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a container definition in a {@link SourceType#C4_L3} grammar and verifies that it is not
     * already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterContainer(final C4L3Parser.ContainerContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a container boundary definition in a {@link SourceType#C4_L3} grammar and verifies that it
     * is not already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterContainer_boundary(final C4L3Parser.Container_boundaryContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a enterprise boundary definition in a {@link SourceType#C4_L1} grammar and verifies that it
     * is not already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterEnterprise_boundary(final C4L1Parser.Enterprise_boundaryContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a enterprise boundary definition in a {@link SourceType#C4_L2} grammar and verifies that it
     * is not already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterEnterprise_boundary(final C4L2Parser.Enterprise_boundaryContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a enterprise boundary definition in a {@link SourceType#C4_L3} grammar and verifies that it
     * is not already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterEnterprise_boundary(final C4L3Parser.Enterprise_boundaryContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a person definition in a {@link SourceType#C4_L1} grammar and verifies that it is not
     * already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterPerson(final C4L1Parser.PersonContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a person definition in a {@link SourceType#C4_L2} grammar and verifies that it is not
     * already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterPerson(final C4L2Parser.PersonContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a person definition in a {@link SourceType#C4_L3} grammar and verifies that it is not
     * already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterPerson(final C4L3Parser.PersonContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of an external person definition in a {@link SourceType#C4_L1} grammar and verifies that it is
     * not already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterPerson_ext(final C4L1Parser.Person_extContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of an external person definition in a {@link SourceType#C4_L2} grammar and verifies that it is
     * not already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterPerson_ext(final C4L2Parser.Person_extContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of an external person definition in a {@link SourceType#C4_L3} grammar and verifies that it is
     * not already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterPerson_ext(final C4L3Parser.Person_extContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a system definition in a {@link SourceType#C4_L1} grammar and verifies that it is not
     * already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterSystem(final C4L1Parser.SystemContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a system definition in a {@link SourceType#C4_L2} grammar and verifies that it is not
     * already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterSystem(final C4L2Parser.SystemContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a system definition in a {@link SourceType#C4_L3} grammar and verifies that it is not
     * already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterSystem(final C4L3Parser.SystemContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of a system boundary definition in a {@link SourceType#C4_L2} grammar and verifies that it is
     * not already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterSystem_boundary(final C4L2Parser.System_boundaryContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of an external system definition in a {@link SourceType#C4_L1} grammar and verifies that it is
     * not already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterSystem_ext(final C4L1Parser.System_extContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of an external system definition in a {@link SourceType#C4_L2} grammar and verifies that it is
     * not already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterSystem_ext(final C4L2Parser.System_extContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    /**
     * Collects the alias of an external system definition in a {@link SourceType#C4_L3} grammar and verifies that it is
     * not already in use.
     * <p>
     * {@inheritDoc}
     */
    @Override
    public void enterSystem_ext(final C4L3Parser.System_extContext ctx) {
        checkAliasIsUnique(ctx.Alias());
    }

    private void checkAliasIsUnique(final TerminalNode alias) {

        if (this.aliases.contains(alias.getText())) {

            final String message = String.format("Alias '%s' is declared multiple times", alias);

            this.reporter.report(message);
            this.rule.getLogger().error(message);
        }

        this.aliases.add(alias.getText());
    }
}