-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodel.go
More file actions
288 lines (253 loc) · 9.95 KB
/
Copy pathmodel.go
File metadata and controls
288 lines (253 loc) · 9.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
package codegraph
import (
"crypto/sha256"
"encoding/json"
"errors"
"fmt"
"sort"
"github.com/compforge/codegraph/internal/analysis"
"github.com/compforge/codegraph/internal/confidence"
"github.com/compforge/codegraph/internal/graphstore"
)
// NodeKind is the concrete code category used both by Node.Kind and Cypher labels.
// +spec=`Each node has exactly its concrete kind as a graph label; symbol is terminology, not a graph category`
type NodeKind string
const (
// DocumentKind represents the input material itself, including opaque gitlinks.
DocumentKind NodeKind = "Document"
Struct NodeKind = "Struct"
Interface NodeKind = "Interface"
Field NodeKind = "Field"
Method NodeKind = "Method"
Function NodeKind = "Function"
// Type represents a named type whose declaration is not a struct or interface
// literal (for example, type ID int); it does not infer an underlying type.
Type NodeKind = "Type"
TypeAlias NodeKind = "TypeAlias"
Class NodeKind = "Class"
Constructor NodeKind = "Constructor"
Variable NodeKind = "Variable"
Constant NodeKind = "Constant"
Module NodeKind = "Module"
Package NodeKind = "Package"
Enum NodeKind = "Enum"
Record NodeKind = "Record"
Namespace NodeKind = "Namespace"
Property NodeKind = "Property"
Trait NodeKind = "Trait"
Macro NodeKind = "Macro"
Union NodeKind = "Union"
)
// Location uses zero-based byte offsets (end exclusive) and one-based lines/columns.
// Columns count bytes, not Unicode code points.
type Location struct {
Path string `json:"path"`
StartByte int `json:"startByte"`
EndByte int `json:"endByte"`
Line int `json:"line"`
Column int `json:"column"`
EndLine int `json:"endLine"`
EndColumn int `json:"endColumn"`
}
// Node is an entity in one snapshot, labeled by its concrete code kind.
// Symbol and Namespace describe overlapping roles of that same entity.
// Location is absent when no single source occurrence owns the entity;
// declares relations retain its contributing source locations.
type Node struct {
ID string `json:"id"`
// Gitlink is set only on an opaque gitlink Document, never on symbols.
Gitlink string `json:"gitlink,omitempty"`
Kind NodeKind `json:"kind"`
Name string `json:"name"`
QualifiedName string `json:"qualifiedName,omitempty"`
Language string `json:"language"`
Location *Location `json:"location,omitempty"`
Markers []Marker `json:"markers,omitempty"`
}
func cloneNode(n Node) Node {
if n.Location != nil {
loc := *n.Location
n.Location = &loc
}
n.Markers = append([]Marker(nil), n.Markers...)
return n
}
func declarationKind(kind string) (NodeKind, error) {
if concrete := analysis.ConcreteKind(kind); concrete != "" {
return NodeKind(concrete), nil
}
return "", fmt.Errorf("unsupported declaration kind %q", kind)
}
type RelationKind string
const (
Contains RelationKind = "contains"
Declares RelationKind = "declares"
Imports RelationKind = "imports"
Calls RelationKind = "calls"
References RelationKind = "references"
Extends RelationKind = "extends"
Implements RelationKind = "implements"
)
// Confidence describes evidence strength, not a calibrated probability.
type Confidence = confidence.Level
const (
Exact = confidence.Exact // established by supported static semantics in the supplied snapshot
Scoped = confidence.Scoped // constrained by bindings, imports, receivers or types
NameOnly = confidence.NameOnly // name match without a proven binding
Heuristic = confidence.Heuristic // convention or incomplete structural similarity
)
// Evidence records one derivation. Location, when present, points to supporting syntax.
type Evidence struct {
Basis string `json:"basis"`
Confidence Confidence `json:"confidence"`
Location *Location `json:"location,omitempty"`
}
// Relation identifies one relation at one source location, including parallel calls.
type Relation struct {
ID string `json:"id"`
Source string `json:"source"`
Target string `json:"target"`
Kind RelationKind `json:"kind"`
// Confidence is the strongest independent Evidence confidence when published.
Confidence Confidence `json:"confidence"`
Evidence []Evidence `json:"evidence"`
Location Location `json:"location"`
}
// Path lists nodes in traversal order; Relations retain their stored direction.
type Path struct {
Nodes []Node `json:"nodes"`
Relations []Relation `json:"relations"`
}
type Subgraph struct {
Nodes []Node `json:"nodes"`
Relations []Relation `json:"relations"`
}
// cloneRelation detaches both the proof list and optional supporting locations.
func cloneRelation(r Relation) Relation {
r.Evidence = append([]Evidence(nil), r.Evidence...)
for i := range r.Evidence {
if r.Evidence[i].Location != nil {
loc := *r.Evidence[i].Location
r.Evidence[i].Location = &loc
}
}
return r
}
// DiagnosticSubject identifies the information a local gap concerns. It does
// not prescribe whether a consumer should expand its analysis or reject a path.
type DiagnosticSubject string
const (
DocumentSubject DiagnosticSubject = "document"
DeclarationsSubject DiagnosticSubject = "declarations"
RelationsSubject DiagnosticSubject = "relations"
ContextSubject DiagnosticSubject = "context"
ResourcesSubject DiagnosticSubject = "resources"
)
// Diagnostic records information that could not be produced. Non-exact edges
// already carry their uncertainty in Confidence and Basis.
// Location covers the whole document when the producer cannot localize the gap.
type Diagnostic struct {
Code string `json:"code"`
Message string `json:"message"`
Subject DiagnosticSubject `json:"subject"`
Relation RelationKind `json:"relation,omitempty"`
Location Location `json:"location"`
Outline *OutlineCoverage `json:"outline,omitempty"`
}
// OutlineCoverage counts query candidates, not all declarations in the source.
// Zero omissions do not prove language coverage. The upstream outline API has
// no omission locations, so these counts apply to the diagnostic's document.
type OutlineCoverage struct {
Symbols int `json:"symbols"`
OmittedNoName int `json:"omittedNoName,omitempty"`
OmittedDuplicate int `json:"omittedDuplicate,omitempty"`
OmittedNameConflict int `json:"omittedNameConflict,omitempty"`
OmittedConflict int `json:"omittedConflict,omitempty"`
OmittedOverlap int `json:"omittedOverlap,omitempty"`
OmittedInvalidNameRange int `json:"omittedInvalidNameRange,omitempty"`
OmittedMultipleDefinitions int `json:"omittedMultipleDefinitions,omitempty"`
OwnerRuleMisses int `json:"ownerRuleMisses,omitempty"`
DeclineReason string `json:"declineReason,omitempty"`
Truncated bool `json:"truncated,omitempty"`
}
func extractionDiagnostic(f analysis.Facts, issue analysis.Issue) Diagnostic {
d := Diagnostic{Code: issue.Code, Message: issue.Message, Subject: DiagnosticSubject(issue.Subject),
Relation: RelationKind(issue.Relation), Location: location(f, issue.Span)}
if issue.Outline != nil {
outline := OutlineCoverage(*issue.Outline)
d.Outline = &outline
}
return d
}
func cloneDiagnostics(in []Diagnostic) []Diagnostic {
out := append([]Diagnostic(nil), in...)
for i := range out {
if out[i].Outline != nil {
outline := *out[i].Outline
out[i].Outline = &outline
}
}
return out
}
type MarkerKind string
const (
Spec MarkerKind = "spec"
Case MarkerKind = "case"
Rule MarkerKind = "rule"
Link MarkerKind = "link"
Doc MarkerKind = "doc"
)
// Marker preserves the annotation payload and its source location.
// Structured case payloads are retained verbatim, not executed or interpreted.
type Marker struct {
Kind MarkerKind `json:"kind"`
Text string `json:"text"`
Location Location `json:"location"`
}
// BuildReport describes the published graph and its local information gaps.
// Build/Wait errors describe execution failures; diagnostics do not invalidate
// unrelated graph facts or prescribe a consumer's fallback policy.
// +spec=`Candidate relations and local gaps remain usable analysis results`
type BuildReport struct {
Snapshot string `json:"snapshot"`
Documents []string `json:"documents"`
Diagnostics []Diagnostic `json:"diagnostics"`
Nodes, Relations int
}
func cloneReport(r BuildReport) BuildReport {
r.Documents = append([]string(nil), r.Documents...)
r.Diagnostics = cloneDiagnostics(r.Diagnostics)
return r
}
// DocumentID identifies a document node by its snapshot-relative logical path.
func DocumentID(name string) string { return "document:" + name }
// declarationID is shared by early detached results and published nodes.
func declarationID(path string, kind NodeKind, qualifiedName string, start int) string {
return "node:" + identity(path, kind, qualifiedName, start)
}
func identity(parts ...any) string {
b, _ := json.Marshal(parts)
h := sha256.Sum256(b)
return fmt.Sprintf("%x", h[:])
}
func location(f analysis.Facts, span analysis.Span) Location {
line := sort.Search(len(f.LineStarts), func(i int) bool { return f.LineStarts[i] > span.Start })
endLine := sort.Search(len(f.LineStarts), func(i int) bool { return f.LineStarts[i] > span.End })
if endLine == 0 {
endLine = 1
}
return Location{Path: f.Path, StartByte: span.Start, EndByte: span.End, Line: line, Column: span.Start - f.LineStarts[line-1] + 1, EndLine: endLine, EndColumn: span.End - f.LineStarts[endLine-1] + 1}
}
func locationPtr(f analysis.Facts, span analysis.Span) *Location {
loc := location(f, span)
return &loc
}
var (
ErrSnapshotChanged = errors.New("source changed within graph snapshot")
ErrDocumentNotFound = errors.New("document not found in graph")
ErrBuildBudget = errors.New("build budget exceeded")
)
var (
ErrQueryBudget = graphstore.ErrBudget
ErrReadOnly = graphstore.ErrReadOnly
)