What I would otherwise forget
Valid July 2017 with swift:master
SourceKit is the component of Swift that provides an API for understanding and manipulating Swift source code. Its conceptual model is higher-level and simpler than the Swift compiler data structures: SourceKit itself builds and processes those data structures to provide what it thinks is useful to clients.
The main client of SourceKit is Xcode. It is pretty clear that changes to the API are made organically to meet Xcode’s needs: the various parts of the API do not hang together as a coherent designed whole. The SourceKit API is not specified publically or much documented – it is not covered by the swift-evolution process. This probably gives us a better Xcode experience but makes it tough/interesting to work with.
The point of this piece is to compare the various APIs and figure out what best to change to improve SourceKitten & clients, particularly Jazzy.
sourcekitd-test -req=structure
and
sourcekitten structure
.
key.syntactic_only: 1
otherwise times out waiting for
sema???)sourcekitd-test -req=doc-info
.
@available
attributes but ignores all
others.structure
to fill in blanks. Issued by
sourcekitd-test -req=cursor
.
sourcekitd-test -req=index
and sourcekitten index
.
So this is a bit of a mess. It looks like structure
and
cursorinfo
should fit together, and this is SourceKitten’s main
strategy, but that leads to problems:
structure
bugs, subscripts and typealiases are missing.
SourceKitten valiantly tries to deal with this by sending cursorinfo
s
after doc-comments that don’t crop up in the structure
. This means
undocumented decls are omitted, and there is no ACL or attribute info for
the documented ones.@available
is … unavailable.Let’s try to figure out why these problems exist. Hope to add the missing
types to structure
but am somewhat resigned to having to add an additional
docinfo
query to SourceKitten in order to access the @available
stuff.
Briefly:
Structure - source.request.editor.open
CursorInfo - source.request.cursorinfo
DocInfo - source.request.docinfo
These APIs are almost entirely independent, each having their own AST-traversal
logic, their own intermediate data structure, and their own serialization logic.
Indexing is separate again. The structure
returned by editoropen
uses an AST
that has only been parsed: the others use a type-checked ‘sema’ed AST.
Would be fascinating to know the development history here – feels like the classic “user interfaces are easy” plus drip-drip of requirements antipatterns.
The fields returned form a classic three-way venn diagram:
Key | editoropen | cursorinfo | docinfo |
---|---|---|---|
kind[1] | Y | Y | Y |
offset[2] | Y | Y | Y |
length[2] | Y | Y | Y |
name | Y | Y | Y |
nameoffset | Y | ||
namelength | Y | ||
bodyoffset | Y | ||
bodylength | Y | ||
usr | Y | Y | |
accesslevel | Y | ||
setteraccesslevel | Y | ||
typename | Y[3] | Y | |
runtime_name | Y[4] | ||
selector_name | Y[5] | ||
attributes | Y[6] | Y[7] | |
full_as_xml | Y | Y[8] | |
annotated_decl | Y | ||
fully_annotated_decl | Y | Y | |
groupname, modulename | Y | ||
localization_key | Y | Y | |
filepath | Y | ||
parent_loc | Y | ||
is_system | Y | ||
typeusr | Y | ||
containertypeusr | Y | ||
unavailable | Y | ||
deprecated | Y | ||
optional | Y | ||
generic_requirements | Y |
Then more complex:
Concept | editoropen | cursorinfo | docinfo |
---|---|---|---|
Inherited classes | inheritedtypes - names | inherits - name/usr/kind | |
Conformed protocols | inheritedtypes - names | conforms - name/usr/kind | |
Overridden class members | overrides - usr | inherits - name/usr/kind | |
Overridden proto members | overrides - usr | conforms - name/usr/kind | |
Extended types | extends - name/usr/kind | ||
Overloaded functions | related_decls | ||
Generic parameters | generic_params - names; generic_type_param entity - name / usr/declaration |
Notes:
editoropen
and docinfo
disagree on parameters. editoropen
generates
a decl.var.parameter
for the argumen, with name correct, offset pointing to
the name of the arg, and length covering the entire arg declaration. But
docinfo
generates a decl.var.local
with the correct name but with
offset and length pointing at the type of the arg. For cursorinfo
the
input offset
must be of the identifier in question, ie. nameoffset
from
editoropen
.@IBAction
s!@attribute
s with stuff like override
that users do not think of as attributes.@available
only, all parameters decoded