001package gudusoft.gsqlparser.ir.semantic;
002
003import java.util.Objects;
004
005/**
006 * A secondary source location that helps explain a {@link Diagnostic}.
007 *
008 * <p>{@code role} is a stable, non-localized machine value such as
009 * {@code first-marker}; {@code message} is user-visible explanatory text.
010 *
011 * <p><b>API status:</b> read-only consumption of analyzer-produced related
012 * locations is part of Join Analysis Consumption Profile v1. Constructors and
013 * factories are producer-oriented and are outside that profile.
014 */
015public final class RelatedLocation {
016
017    private final String role;
018    private final String message;
019    private final SourceSpan span;
020
021    public RelatedLocation(String role, String message, SourceSpan span) {
022        this.role = requireNonEmpty(role, "role");
023        this.message = requireNonEmpty(message, "message");
024        this.span = Objects.requireNonNull(span, "span");
025    }
026
027    public static RelatedLocation of(String role, String message, SourceSpan span) {
028        return new RelatedLocation(role, message, span);
029    }
030
031    public String getRole() {
032        return role;
033    }
034
035    public String getMessage() {
036        return message;
037    }
038
039    public SourceSpan getSpan() {
040        return span;
041    }
042
043    private static String requireNonEmpty(String value, String name) {
044        Objects.requireNonNull(value, name);
045        if (value.trim().isEmpty()) {
046            throw new IllegalArgumentException(name + " must not be empty");
047        }
048        return value;
049    }
050
051    @Override
052    public boolean equals(Object o) {
053        if (this == o) return true;
054        if (!(o instanceof RelatedLocation)) return false;
055        RelatedLocation that = (RelatedLocation) o;
056        return role.equals(that.role)
057                && message.equals(that.message)
058                && span.equals(that.span);
059    }
060
061    @Override
062    public int hashCode() {
063        return Objects.hash(role, message, span);
064    }
065
066    @Override
067    public String toString() {
068        return role + ": " + message + " at " + span;
069    }
070}