UNPKG

plaxtony

Version:

Static code analysis of SC2 Galaxy Script

126 lines (103 loc) 4.56 kB
import * as lsp from 'vscode-languageserver'; import * as gt from '../compiler/types'; import { AbstractProvider } from './provider'; import { Diagnostic, DiagnosticCategory } from '../compiler/types'; import { TypeChecker } from '../compiler/checker'; import { unbindSourceFile } from '../compiler/binder'; import { getLineAndCharacterOfPosition } from './utils'; import { logger } from '../common'; import URI from 'vscode-uri'; import { QualifiedSourceFile } from './store'; export function formatDiagnosticTotal(summary: DiagnosticWorkspaceSummary) { const so: string[] = []; for (const [uri, dlist] of summary.diagnostics) { const qs = summary.sourceFiles.get(uri); so.push(`"${qs.s2meta.docName}" ${uri}\n`); for (const dg of dlist) { so.push(`\n[${DiagnosticCategory[dg.category].toUpperCase()}] ${dg.messageText}`); so.push(`\n in ${URI.parse(uri).fsPath}:${dg.line + 1}:${dg.col}\n\n`); } } so.push('\n\n'); so.push(`Processed ${summary.filesProcessed} files.\n\n`); for (const item of Object.keys(DiagnosticCategory).filter(v => typeof (DiagnosticCategory as any)[v] === 'number')) { so.push('='); so.push(summary.issuesTotal[DiagnosticCategory[item as keyof typeof DiagnosticCategory]].toString().padStart(6)); so.push(` ${item}s\n`); } return so.join(''); } export interface DiagnosticWorkspaceSummary { diagnostics: Map<string, Diagnostic[]>; sourceFiles: Map<string, QualifiedSourceFile>; filesProcessed: number; issuesTotal: { [DiagnosticCategory.Error]: number; [DiagnosticCategory.Warning]: number; [DiagnosticCategory.Message]: number; [DiagnosticCategory.Hint]: number; }; } export type DiagnosticsCallback = (a: string) => void; export class DiagnosticsProvider extends AbstractProvider { private reporter?: DiagnosticsCallback; private translateDiagnostics(sourceFile: gt.SourceFile, origDiagnostics: gt.Diagnostic[], source: string): lsp.Diagnostic[] { let lspDiagnostics: lsp.Diagnostic[] = []; for (let dg of origDiagnostics) { const tmp = <lsp.Diagnostic>{ severity: dg.category, range: { start: getLineAndCharacterOfPosition(sourceFile, dg.start), end: getLineAndCharacterOfPosition(sourceFile, dg.start + dg.length) }, message: dg.messageText, source, }; if (tmp.tags) { tmp.tags = dg.tags; } lspDiagnostics.push(tmp); } return lspDiagnostics; } public subscribe(uri: string) { } public checkFile(documentUri: string) { const checker = new TypeChecker(this.store); const sourceFile = this.store.documents.get(documentUri); unbindSourceFile(sourceFile, this.store); sourceFile.additionalSyntacticDiagnostics = checker.checkSourceFile(sourceFile, true); } public provideDiagnostics(uri: string): lsp.Diagnostic[] { const sourceFile = this.store.documents.get(uri); let parseDiag = sourceFile.parseDiagnostics; let checkerDiag = sourceFile.additionalSyntacticDiagnostics; logger.info(`${uri} - ${parseDiag.length} - ${checkerDiag.length}`); if (parseDiag.length > 100) parseDiag = parseDiag.slice(0, 100); if (checkerDiag.length > 100) checkerDiag = checkerDiag.slice(0, 100); return [].concat( this.translateDiagnostics(sourceFile, parseDiag, 'parser'), this.translateDiagnostics(sourceFile, checkerDiag, 'typecheck') ); } public checkFileRecursively(documentUri: string) { const checker = new TypeChecker(this.store); const sourceFile = this.store.documents.get(documentUri); const result = checker.checkSourceFileRecursively(sourceFile); const dsum: DiagnosticWorkspaceSummary = { diagnostics: result.diagnostics, sourceFiles: result.sourceFiles, filesProcessed: result.sourceFiles.size, issuesTotal: { [DiagnosticCategory.Error]: 0, [DiagnosticCategory.Warning]: 0, [DiagnosticCategory.Message]: 0, [DiagnosticCategory.Hint]: 0, }, }; for (const itDg of result.diagnostics.values()) { itDg.forEach(v => ++dsum.issuesTotal[v.category]) } return dsum; } }