| // 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) |
| } |