| // Copyright 2020 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 analysis |
| |
| import ( |
| "fmt" |
| |
| "fidl-lsp/third_party/fidlgen" |
| |
| "fidl-lsp/state" |
| ) |
| |
| // TypeOfSymbol returns the type information of `sym`. |
| // |
| // analysis.Type contains all the information needed to create a human-readable |
| // description of the type. |
| func (a *Analyzer) TypeOfSymbol(fs *state.FileSystem, sym state.Symbol) (Type, error) { |
| // If `sym` is a library name, return a `library`-kinded TypeInfo. |
| libName, err := fidlgen.ReadLibraryName(sym.Name) |
| if err == nil { |
| // TODO: We could use getLibraryWithFile here, but it would be more |
| // complicated: if this library name is a declaration, we should pass it |
| // the file the symbol is in; but if it's a library import, we should |
| // pass it a file of that imported library. |
| if _, isLib := a.getLibrary(libName); isLib { |
| return Type{ |
| IsLib: true, |
| }, nil |
| } |
| } |
| |
| // Otherwise, we assume it is a local or fully-qualified name |
| name, err := a.symbolToFullyQualifiedName(fs, sym) |
| if err != nil { |
| return Type{}, fmt.Errorf( |
| "could not convert symbol `%s` to fully-qualified name: %s", |
| sym.Name, |
| err, |
| ) |
| } |
| |
| var symInfo *symbolInfo |
| if name.lib != nil { |
| symInfo, err = a.lookupSymbolInfoInLibrary(name.name, name.lib) |
| if err != nil { |
| return Type{}, fmt.Errorf( |
| "could not find type of symbol `%s`: %s", |
| name.name.FullyQualifiedName(), |
| err, |
| ) |
| } |
| } else { |
| symInfo, err = a.lookupSymbolInfo(name.name) |
| if err != nil { |
| return Type{}, fmt.Errorf( |
| "could not find type of symbol `%s`: %s", |
| name.name.FullyQualifiedName(), |
| err, |
| ) |
| } |
| } |
| |
| // Resolve identifier type, if necessary. |
| if symInfo.typeInfo.Kind == IdentifierType && !symInfo.typeInfo.Identifier.IsDecl { |
| // This means that rather than being a declaration, symInfo is a value |
| // of an identifier type, so we lookup that type's info based on the |
| // type name. |
| typeName, err := fidlgen.ReadName(symInfo.typeInfo.Identifier.Identifier) |
| if err != nil { |
| return Type{}, fmt.Errorf( |
| "invalid identifier type `%s`: %s", |
| symInfo.typeInfo.Identifier.Identifier, |
| err, |
| ) |
| } |
| t, err := a.lookupSymbolInfo(typeName) |
| if err != nil { |
| return Type{}, fmt.Errorf( |
| "could not find identifier type `%s` of symbol `%s`: %s", |
| typeName.FullyQualifiedName(), |
| name.name.FullyQualifiedName(), |
| err, |
| ) |
| } |
| identifierType := t.typeInfo |
| identifierType.Identifier.IsDecl = false |
| identifierType.Identifier.Nullable = symInfo.typeInfo.Identifier.Nullable |
| identifierType.Identifier.Identifier = symInfo.typeInfo.Identifier.Identifier |
| return identifierType, nil |
| } |
| |
| // Resolve aliased identifier type, if necessary. |
| if symInfo.typeInfo.Kind == IdentifierType && |
| symInfo.typeInfo.Identifier.Kind == TypeAliasKind && |
| symInfo.typeInfo.Identifier.TypeAlias.Type.Kind == IdentifierType { |
| // This means that `sym` is a type alias to an identifier type, so we |
| // need to lookup that identifier type's info based on the type name. |
| aliasedType := symInfo.typeInfo.Identifier.TypeAlias.Type |
| typeName, err := fidlgen.ReadName(aliasedType.Identifier.Identifier) |
| if err != nil { |
| return Type{}, fmt.Errorf( |
| "invalid identifier type `%s`: %s", |
| aliasedType.Identifier.Identifier, |
| err, |
| ) |
| } |
| t, err := a.lookupSymbolInfo(typeName) |
| if err != nil { |
| return Type{}, fmt.Errorf( |
| "could not find identifier type `%s` of symbol `%s`: %s", |
| typeName.FullyQualifiedName(), |
| name.name.FullyQualifiedName(), |
| err, |
| ) |
| } |
| identifierType := t.typeInfo |
| identifierType.Identifier.Nullable = aliasedType.Identifier.Nullable |
| identifierType.Identifier.Identifier = aliasedType.Identifier.Identifier |
| symInfo.typeInfo.Identifier.TypeAlias.Type = identifierType |
| } |
| |
| return symInfo.typeInfo, nil |
| } |