blob: 95e0be7b3c59b25885526e03b2be09a3a1c26da6 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Package summarize produces a FIDL API summary from FIDL IR.
package summarize
import (
"encoding/json"
"io"
"sort"
"go.fuchsia.dev/fuchsia/tools/fidl/lib/fidlgen"
)
type summary []element
// IsEmptyLibrary returns true if the summary contains only an empty library.
func (s summary) IsEmptyLibrary() bool {
if len(s) != 1 {
return false
}
_, isLibrary := s[0].(*library)
return isLibrary
}
// WriteJSON writes out the summary as JSON.
func (s summary) WriteJSON(w io.Writer) error {
e := json.NewEncoder(w)
// 4-level indent is chosen to match `fx format-code`.
e.SetIndent("", " ")
e.SetEscapeHTML(false)
return e.Encode(serialize([]element(s)))
}
// element describes a single platform surface element.
type element interface {
// Member returns true if the Element is a member of something.
Member() bool
// Name returns the fully-qualified name of this Element. For example,
// "library/protocol.Method".
Name() Name
// Serialize converts an Element into a serializable representation.
Serialize() ElementStr
}
var _ = []element{
(*aConst)(nil),
(*aggregate)(nil),
(*alias)(nil),
(*bits)(nil),
(*enum)(nil),
(*library)(nil),
(*member)(nil),
(*method)(nil),
(*protocol)(nil),
}
type summarizer struct {
elements elementSlice
symbols symbolTable
}
// addElement adds an element for summarization.
func (s *summarizer) addElement(e element) {
s.elements = append(s.elements, e)
}
// addUnions adds the elements corresponding to the FIDL unions.
func (s *summarizer) addUnions(unions []fidlgen.Union) {
for _, st := range unions {
for _, m := range st.Members {
s.addElement(newMember(
&s.symbols, st.Name, m.Name, m.Type, fidlgen.UnionDeclType, m.Ordinal, nil))
}
s.addElement(
newAggregateWithStrictness(
st.Name, st.Resourceness, fidlgen.UnionDeclType, st.Strictness))
}
}
// addTables adds the elements corresponding to the FIDL tables.
func (s *summarizer) addTables(tables []fidlgen.Table) {
for _, st := range tables {
for _, m := range st.Members {
s.addElement(newMember(&s.symbols, st.Name, m.Name, m.Type, fidlgen.TableDeclType, m.Ordinal, nil))
}
s.addElement(newAggregate(st.Name, st.Resourceness, fidlgen.TableDeclType))
}
}
// addStructs adds the elements corresponding to the FIDL structs.
func (s *summarizer) addStructs(structs []fidlgen.Struct) {
for _, st := range structs {
for idx, m := range st.Members {
oneBased := idx + 1
s.addElement(newMember(
&s.symbols, st.Name, m.Name, m.Type, fidlgen.StructDeclType, oneBased, m.MaybeDefaultValue))
}
s.addElement(newAggregate(st.Name, st.Resourceness, fidlgen.StructDeclType))
}
}
// registerStructs registers names of all the structs in the FIDL IR.
func (s *summarizer) registerStructs(structs []fidlgen.Struct) {
for _, st := range structs {
st := st
s.symbols.addStruct(st.Name, &st)
}
}
func serialize(e []element) []ElementStr {
var ret []ElementStr
for _, l := range e {
ret = append(ret, l.Serialize())
}
return ret
}
// filterStructs filters out structs that should not be included in API summaries.
func filterStructs(structs []fidlgen.Struct) []fidlgen.Struct {
var out []fidlgen.Struct
for _, s := range structs {
if s.IsEmptySuccessStruct {
continue
}
out = append(out, s)
}
return out
}
// filterUnions filters out unions that should not be included in API summaries.
func filterUnions(unions []fidlgen.Union) []fidlgen.Union {
var out []fidlgen.Union
for _, u := range unions {
if u.IsResult {
continue
}
out = append(out, u)
}
return out
}
// Summarize converts FIDL IR to an API summary.
func Summarize(root fidlgen.Root) summary {
var s summarizer
s.registerStructs(root.Structs)
s.registerStructs(root.ExternalStructs)
s.registerProtocolNames(root.Protocols)
s.addConsts(root.Consts)
s.addBits(root.Bits)
s.addEnums(root.Enums)
s.addStructs(filterStructs(root.Structs))
s.addTables(root.Tables)
s.addUnions(filterUnions(root.Unions))
s.addProtocols(root.Protocols)
s.addElement(&library{r: root})
// TODO(https://fxbug.dev/42158155): Add aliases.
sort.Sort(s.elements)
return summary(s.elements)
}