| // 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 ( |
| "encoding/json" |
| "fmt" |
| "os/exec" |
| |
| fidlcommon "fidl-lsp/third_party/common" |
| |
| "fidl-lsp/state" |
| ) |
| |
| // DiagnosticsOnLibrary retrieves the cached diagnostics for `lib`. |
| func (a *Analyzer) DiagnosticsOnLibrary(lib fidlcommon.LibraryName) (map[state.FileID][]Diagnostic, error) { |
| if _, ok := a.libs[lib]; !ok { |
| return nil, fmt.Errorf("could not find library `%s`", lib) |
| } |
| return a.libs[lib].diags, nil |
| } |
| |
| type fidlLintSuggestion struct { |
| Description string |
| } |
| |
| type FidlcTool string |
| |
| const ( |
| Fidlc FidlcTool = "fidlc" |
| FidlLint = "fidl-lint" |
| ) |
| |
| // Diagnostic represents an {error, warning, lint} deserialized from the JSON |
| // output of fidlc or fidl-lint. |
| type Diagnostic struct { |
| Source FidlcTool |
| Category string |
| Message string |
| Path string |
| StartLine int `json:"start_line"` |
| StartChar int `json:"start_char"` |
| EndLine int `json:"end_line"` |
| EndChar int `json:"end_char"` |
| Suggestions []fidlLintSuggestion |
| } |
| |
| func (a *Analyzer) fidlcDiagsFromStderr(stderr []byte) (map[state.FileID][]Diagnostic, error) { |
| // Deserialize stderr into []Diagnostic |
| var diags []Diagnostic |
| if err := json.Unmarshal(stderr, &diags); err != nil { |
| return nil, fmt.Errorf("could not deserialize fidlc diagnostics: `%s`", err) |
| } |
| fileToDiags := make(map[state.FileID][]Diagnostic) |
| for i := range diags { |
| fileID, err := a.inputFileToFileID(diags[i].Path) |
| if err != nil { |
| continue |
| } |
| if _, ok := fileToDiags[fileID]; !ok { |
| fileToDiags[fileID] = []Diagnostic{} |
| } |
| diags[i].Source = Fidlc |
| fileToDiags[fileID] = append(fileToDiags[fileID], diags[i]) |
| } |
| return fileToDiags, nil |
| } |
| |
| func (a *Analyzer) runFidlLint(path string) (map[state.FileID][]Diagnostic, error) { |
| // TODO: return early with an error if we got status code != 0 or 1? |
| // Otherwise, ignore err: we expect this to fail with status code 1 if there |
| // are any lints from fidl-lint. |
| out, _ := exec.Command(a.cfg.FidlLintPath, "--format=json", path).Output() |
| |
| // Deserialize stdout into []fidlLint |
| var diags []Diagnostic |
| if err := json.Unmarshal(out, &diags); err != nil { |
| return nil, fmt.Errorf("error deserializing fidl-lint output: %s", err) |
| } |
| fileToDiags := make(map[state.FileID][]Diagnostic) |
| for i := range diags { |
| fileID, err := a.inputFileToFileID(diags[i].Path) |
| if err != nil { |
| continue |
| } |
| if _, ok := fileToDiags[fileID]; !ok { |
| fileToDiags[fileID] = []Diagnostic{} |
| } |
| diags[i].Source = FidlLint |
| fileToDiags[fileID] = append(fileToDiags[fileID], diags[i]) |
| } |
| return fileToDiags, nil |
| } |