001package gudusoft.gsqlparser.resolver2.binding; 002 003import java.util.Objects; 004import java.util.Optional; 005 006/** 007 * Source-location and clause attribution for a {@link BindingReference} or 008 * {@link BindingDiagnostic}. 009 * 010 * <p>Immutable; build via {@link #builder()}. Plan ยง7.3 S6 lists the fields 011 * exposed: statement-index, clause, optional line/column, scope kind, and the 012 * raw reference text.</p> 013 */ 014public final class BindingReferenceSite { 015 016 private final int statementIndex; 017 private final BindingClause clause; 018 private final Integer line; 019 private final Integer column; 020 private final String scopeKind; 021 private final String referenceText; 022 023 private BindingReferenceSite(Builder b) { 024 if (b.clause == null) { 025 throw new IllegalArgumentException("BindingReferenceSite.clause is required"); 026 } 027 if (b.referenceText == null || b.referenceText.isEmpty()) { 028 throw new IllegalArgumentException("BindingReferenceSite.referenceText is required"); 029 } 030 this.statementIndex = b.statementIndex; 031 this.clause = b.clause; 032 this.line = b.line; 033 this.column = b.column; 034 this.scopeKind = b.scopeKind; 035 this.referenceText = b.referenceText; 036 } 037 038 public static Builder builder() { 039 return new Builder(); 040 } 041 042 public int statementIndex() { 043 return statementIndex; 044 } 045 046 public BindingClause clause() { 047 return clause; 048 } 049 050 public Optional<Integer> line() { 051 return Optional.ofNullable(line); 052 } 053 054 public Optional<Integer> column() { 055 return Optional.ofNullable(column); 056 } 057 058 public Optional<String> scopeKind() { 059 return Optional.ofNullable(scopeKind); 060 } 061 062 public String referenceText() { 063 return referenceText; 064 } 065 066 @Override 067 public boolean equals(Object o) { 068 if (this == o) return true; 069 if (!(o instanceof BindingReferenceSite)) return false; 070 BindingReferenceSite that = (BindingReferenceSite) o; 071 return statementIndex == that.statementIndex 072 && clause == that.clause 073 && Objects.equals(line, that.line) 074 && Objects.equals(column, that.column) 075 && Objects.equals(scopeKind, that.scopeKind) 076 && referenceText.equals(that.referenceText); 077 } 078 079 @Override 080 public int hashCode() { 081 return Objects.hash(statementIndex, clause, line, column, scopeKind, referenceText); 082 } 083 084 @Override 085 public String toString() { 086 StringBuilder sb = new StringBuilder("BindingReferenceSite{stmt=").append(statementIndex) 087 .append(' ').append(clause).append(" text=").append(referenceText); 088 if (line != null) sb.append(" line=").append(line); 089 if (column != null) sb.append(" col=").append(column); 090 if (scopeKind != null) sb.append(" scope=").append(scopeKind); 091 return sb.append('}').toString(); 092 } 093 094 public static final class Builder { 095 096 private int statementIndex; 097 private BindingClause clause; 098 private Integer line; 099 private Integer column; 100 private String scopeKind; 101 private String referenceText; 102 103 private Builder() { 104 } 105 106 public Builder statementIndex(int v) { 107 this.statementIndex = v; 108 return this; 109 } 110 111 public Builder clause(BindingClause v) { 112 this.clause = v; 113 return this; 114 } 115 116 public Builder line(int v) { 117 this.line = v; 118 return this; 119 } 120 121 public Builder column(int v) { 122 this.column = v; 123 return this; 124 } 125 126 public Builder scopeKind(String v) { 127 this.scopeKind = v; 128 return this; 129 } 130 131 public Builder referenceText(String v) { 132 this.referenceText = v; 133 return this; 134 } 135 136 public BindingReferenceSite build() { 137 return new BindingReferenceSite(this); 138 } 139 } 140}