diff --git a/docs/issue_template.md b/docs/issue_template.md index e0c88aa71..41301510d 100644 --- a/docs/issue_template.md +++ b/docs/issue_template.md @@ -1,68 +1,23 @@ - - - - - - ### Brief Issue Summary -### Expected: - - - -1. Push button -2. Thing happens - -### Apparent Behavior: - - + - +### CMake Tools Diagnostics - - -1. Push button -2. Nothing happens - -### CMake Tools Log - - + ``` - + ``` -### Developer Tools Log +### Debug Log - + ``` - + ``` - -### Platform and Versions - - - -- **Operating System**: -- **CMake Version**: -- **VSCode Version**: -- **CMake Tools Extension Version**: -- **Compiler/Toolchain**: - -### Other Notes/Information - - diff --git a/package.json b/package.json index e07e162a8..b58a51493 100644 --- a/package.json +++ b/package.json @@ -144,6 +144,12 @@ "when": "cmake:enableFullFeatureSet", "category": "CMake" }, + { + "command": "cmake.logDiagnostics", + "title": "%cmake-tools.command.cmake.logDiagnostics.title%", + "when": "cmake:enableFullFeatureSet", + "category": "CMake" + }, { "command": "cmake.selectActiveFolder", "title": "%cmake-tools.command.cmake.selectActiveFolder.title%", diff --git a/package.nls.json b/package.nls.json index f441c1ddb..cb0f7c47d 100644 --- a/package.nls.json +++ b/package.nls.json @@ -7,6 +7,7 @@ "cmake-tools.command.cmake.selectBuildPreset.title": "Select Build Preset", "cmake-tools.command.cmake.selectTestPreset.title": "Select Test Preset", "cmake-tools.command.cmake.viewLog.title": "Open the CMake Tools Log File", + "cmake-tools.command.cmake.logDiagnostics.title": "Log Diagnostics", "cmake-tools.command.cmake.editKits.title": "Edit User-Local CMake Kits", "cmake-tools.command.cmake.scanForKits.title": "Scan for Kits", "cmake-tools.command.cmake.scanForCompilers.title": "Scan for Compilers", diff --git a/src/cpptools.ts b/src/cpptools.ts index b71471d0a..7c8911e75 100644 --- a/src/cpptools.ts +++ b/src/cpptools.ts @@ -14,6 +14,7 @@ import * as path from 'path'; import * as vscode from 'vscode'; import * as cpt from 'vscode-cpptools'; import * as nls from 'vscode-nls'; +import { TargetTypeString } from './drivers/cms-client'; nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })(); const localize: nls.LocalizeFunc = nls.loadMessageBundle(); @@ -24,6 +25,22 @@ type Architecture = 'x86' | 'x64' | 'arm' | 'arm64' | undefined; type StandardVersion = "c89" | "c99" | "c11" | "c17" | "c++98" | "c++03" | "c++11" | "c++14" | "c++17" | "c++20" | "gnu89" | "gnu99" | "gnu11" | "gnu17" | "gnu++98" | "gnu++03" | "gnu++11" | "gnu++14" | "gnu++17" | "gnu++20" | undefined; +export interface DiagnosticsCpptools { + isReady: boolean; + hasCodeModel: boolean; + targetCount: number; + executablesCount: number; + librariesCount: number; + targets: DiagnosticsTarget[]; + requests: string[]; + responses: cpt.SourceFileConfigurationItem[]; +} + +export interface DiagnosticsTarget { + name: string; + type: TargetTypeString; +} + export interface CompileFlagInformation { extraDefinitions: string[]; standard?: StandardVersion; @@ -324,30 +341,48 @@ export class CppConfigurationProvider implements cpt.CustomConfigurationProvider * Test if we are able to provide a configuration for the given URI * @param uri The URI to look up */ - async canProvideConfiguration(uri: vscode.Uri) { return !!this._getConfiguration(uri); } + async canProvideConfiguration(uri: vscode.Uri) { + this.requests.add(uri.toString()); + return !!this._getConfiguration(uri); + } + + private requests = new Set(); + private responses = new Map(); /** * Get the configurations for the given URIs. URIs for which we have no * configuration are simply ignored. * @param uris The file URIs to look up */ - async provideConfigurations(uris: vscode.Uri[]) { return util.dropNulls(uris.map(u => this._getConfiguration(u))); } + async provideConfigurations(uris: vscode.Uri[]) { + const configs = util.dropNulls(uris.map(u => this._getConfiguration(u))); + configs.forEach(config => { + this.responses.set(config.uri.toString(), config); + }); + return configs; + } /** * A request to determine whether this provider can provide a code browsing configuration for the workspace folder. * @param token (optional) The cancellation token. * @returns 'true' if this provider can provider a code browsing configuration for the workspace folder. */ - async canProvideBrowseConfiguration() { return true; } + async canProvideBrowseConfiguration() { + return true; + } /** * A request to get the code browsing configuration for the workspace folder. * @returns A [WorkspaceBrowseConfiguration](#WorkspaceBrowseConfiguration) with the information required to * construct the equivalent of `browse.path` from `c_cpp_properties.json`. */ - async provideBrowseConfiguration() { return this._workspaceBrowseConfiguration; } + async provideBrowseConfiguration() { + return this._workspaceBrowseConfiguration; + } - async canProvideBrowseConfigurationsPerFolder() { return true; } + async canProvideBrowseConfigurationsPerFolder() { + return true; + } async provideFolderBrowseConfiguration(_uri: vscode.Uri): Promise { return this._workspaceBrowseConfigurations.get(util.platformNormalizePath(_uri.fsPath)) ?? this._workspaceBrowseConfiguration; @@ -397,8 +432,7 @@ export class CppConfigurationProvider implements cpt.CustomConfigurationProvider } const targetFromToolchains = comp_toolchains?.target; - const targetArchFromToolchains = targetFromToolchains - ? parseTargetArch(targetFromToolchains) : undefined; + const targetArchFromToolchains = targetFromToolchains ? parseTargetArch(targetFromToolchains) : undefined; const normalizedCompilerPath = util.platformNormalizePath(comp_path); const flags = fileGroup.compileFlags ? [...shlex.split(fileGroup.compileFlags)] : target.compileFlags; @@ -487,11 +521,18 @@ export class CppConfigurationProvider implements cpt.CustomConfigurationProvider this._cpptoolsVersion = value; } + private targets: DiagnosticsTarget[] = []; + /** * Update the file index and code model * @param opts Update parameters */ updateConfigurationData(opts: codemodel_api.CodeModelParams) { + // Reset the counters for diagnostics + this.requests.clear(); + this.responses.clear(); + this.targets = []; + let hadMissingCompilers = false; this._workspaceBrowseConfiguration = {browsePath: []}; this._activeTarget = opts.activeTarget; @@ -509,6 +550,7 @@ export class CppConfigurationProvider implements cpt.CustomConfigurationProvider const compileFlags = [...util.flatMap(grps, grp => shlex.split(grp.compileFlags || ''))]; const defines = [...new Set(util.flatMap(grps, grp => grp.defines || []))]; const sysroot = target.sysroot || ''; + this.targets.push({ name: target.name, type: target.type }); for (const grp of target.fileGroups || []) { try { this._updateFileGroup( @@ -542,4 +584,22 @@ export class CppConfigurationProvider implements cpt.CustomConfigurationProvider } this._lastUpdateSucceeded = !hadMissingCompilers; } + + private ready: boolean = false; + markAsReady() { + this.ready = true; + } + + getDiagnostics(): DiagnosticsCpptools { + return { + isReady: this.ready, + hasCodeModel: this._fileIndex.size > 0, + requests: [...this.requests.values() ], + responses: [...this.responses.values()], + targetCount: this.targets.length, + executablesCount: this.targets.reduce((acc, target) => target.type === 'EXECUTABLE' ? acc + 1 : acc, 0), + librariesCount: this.targets.reduce((acc, target) => target.type.endsWith('LIBRARY') ? acc + 1 : acc, 0), + targets: this.targets.length < 20 ? this.targets : [] + }; + } } diff --git a/src/drivers/driver.ts b/src/drivers/driver.ts index c8fac6a14..64eaa0e70 100644 --- a/src/drivers/driver.ts +++ b/src/drivers/driver.ts @@ -29,6 +29,7 @@ import * as nls from 'vscode-nls'; import { majorVersionSemver, minorVersionSemver, parseTargetTriple, TargetTriple } from '@cmt/triple'; import * as preset from '@cmt/preset'; import * as codemodel from '@cmt/drivers/codemodel-driver-interface'; +import {DiagnosticsConfiguration} from '@cmt/folders'; nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })(); const localize: nls.LocalizeFunc = nls.loadMessageBundle(); @@ -1219,14 +1220,14 @@ export abstract class CMakeDriver implements vscode.Disposable { let telemetryProperties: telemetry.Properties; if (this.useCMakePresets) { telemetryProperties = { - CMakeExecutableVersion: cmakeVersion ? `${cmakeVersion.major}.${cmakeVersion.minor}.${cmakeVersion.patch}` : '', + CMakeExecutableVersion: cmakeVersion ? util.versionToString(cmakeVersion) : '', CMakeGenerator: this.generatorName || '', Preset: this.useCMakePresets ? 'true' : 'false', Trigger: trigger }; } else { telemetryProperties = { - CMakeExecutableVersion: cmakeVersion ? `${cmakeVersion.major}.${cmakeVersion.minor}.${cmakeVersion.patch}` : '', + CMakeExecutableVersion: cmakeVersion ? util.versionToString(cmakeVersion) : '', CMakeGenerator: this.generatorName || '', ConfigType: this.isMultiConf ? 'MultiConf' : this.currentBuildType || '', Toolchain: this._kit?.toolchainFile ? 'true' : 'false', // UseToolchain? @@ -1672,4 +1673,17 @@ export abstract class CMakeDriver implements vscode.Disposable { return inst; } + public getDiagnostics(): DiagnosticsConfiguration { + return { + folder: this.workspaceFolder || '', + cmakeVersion: this.cmake.version ? util.versionToString(this.cmake.version) : '', + configured: this._isConfiguredAtLeastOnce, + generator: this.generatorName || '', + usesPresets: this.useCMakePresets, + compilers: { + C: this.cmakeCacheEntries.get('CMAKE_C_COMPILER')?.value, + CXX: this.cmakeCacheEntries.get('CMAKE_CXX_COMPILER')?.value + } + }; + } } diff --git a/src/extension.ts b/src/extension.ts index c2381e521..13c205bf7 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -14,8 +14,8 @@ import * as nls from 'vscode-nls'; import {CMakeCache} from '@cmt/cache'; import {CMakeTools, ConfigureType, ConfigureTrigger} from '@cmt/cmake-tools'; import {ConfigurationReader, TouchBarConfig} from '@cmt/config'; -import {CppConfigurationProvider} from '@cmt/cpptools'; -import {CMakeToolsFolderController, CMakeToolsFolder} from '@cmt/folders'; +import {CppConfigurationProvider, DiagnosticsCpptools} from '@cmt/cpptools'; +import {CMakeToolsFolderController, CMakeToolsFolder, DiagnosticsConfiguration, DiagnosticsSettings} from '@cmt/folders'; import { Kit, USER_KITS_FILEPATH, @@ -38,7 +38,8 @@ import {ProgressHandle, DummyDisposable, reportProgress} from '@cmt/util'; import {DEFAULT_VARIANTS} from '@cmt/variant'; import {expandString, KitContextVars} from '@cmt/expand'; import paths from '@cmt/paths'; -import { CMakeDriver, CMakePreconditionProblems } from './drivers/driver'; +import {CMakeDriver, CMakePreconditionProblems} from './drivers/driver'; +import {platform} from 'os'; nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })(); const localize: nls.LocalizeFunc = nls.loadMessageBundle(); @@ -61,6 +62,15 @@ let _EXT_MANAGER: ExtensionManager|null = null; type CMakeToolsMapFn = (cmt: CMakeTools) => Thenable; type CMakeToolsQueryMapFn = (cmt: CMakeTools) => Thenable; +interface Diagnostics { + os: string; + vscodeVersion: string; + cmtVersion: string; + configurations: DiagnosticsConfiguration[]; + settings: DiagnosticsSettings[]; + cpptoolsIntegration: DiagnosticsCpptools; +} + /** * A class to manage the extension. * @@ -296,7 +306,7 @@ class ExtensionManager implements vscode.Disposable { */ private readonly _configProvider = new CppConfigurationProvider(); private _cppToolsAPI?: cpt.CppToolsApi; - private _configProviderRegister?: Promise; + private _configProviderRegistered?: boolean = false; private _checkFolderArgs(folder?: vscode.WorkspaceFolder): CMakeToolsFolder | undefined { let cmtFolder: CMakeToolsFolder | undefined; @@ -742,14 +752,16 @@ class ExtensionManager implements vscode.Disposable { } ); } - await this.ensureCppToolsProviderRegistered(); + this.ensureCppToolsProviderRegistered(); if (cpptools.notifyReady && this.cpptoolsNumFoldersReady < this._folders.size) { ++this.cpptoolsNumFoldersReady; if (this.cpptoolsNumFoldersReady === this._folders.size) { cpptools.notifyReady(this._configProvider); + this._configProvider.markAsReady(); } } else { cpptools.didChangeCustomConfiguration(this._configProvider); + this._configProvider.markAsReady(); } } }); @@ -1019,18 +1031,17 @@ class ExtensionManager implements vscode.Disposable { return this._folders.get(folder)?.useCMakePresets; } - async ensureCppToolsProviderRegistered() { - if (!this._configProviderRegister) { - this._configProviderRegister = this._doRegisterCppTools(); + ensureCppToolsProviderRegistered() { + if (!this._configProviderRegistered) { + this._doRegisterCppTools(); + this._configProviderRegistered = true; } - return this._configProviderRegister; } - async _doRegisterCppTools() { - if (!this._cppToolsAPI) { - return; + _doRegisterCppTools() { + if (this._cppToolsAPI) { + this._cppToolsAPI.registerCustomConfigurationProvider(this._configProvider); } - this._cppToolsAPI.registerCustomConfigurationProvider(this._configProvider); } private _cleanOutputChannel() { @@ -1351,6 +1362,29 @@ class ExtensionManager implements vscode.Disposable { await logging.showLogFile(); } + async logDiagnostics() { + telemetry.logEvent("logDiagnostics"); + const configurations: DiagnosticsConfiguration[] = []; + const settings: DiagnosticsSettings[] = []; + for (const folder of this._folders.getAll()) { + configurations.push(await folder.getDiagnostics()); + settings.push(await folder.getSettingsDiagnostics()); + } + + const result: Diagnostics = { + os: platform(), + vscodeVersion: vscode.version, + cmtVersion: util.thisExtensionPackage().version, + configurations, + cpptoolsIntegration: this._configProvider.getDiagnostics(), + settings + }; + const output = logging.channelManager.get("CMake Diagnostics"); + output.clear(); + output.appendLine(JSON.stringify(result, null, 2)); + output.show(); + } + activeFolderName(): string { return this._folders.activeFolder?.folder.name || ''; } @@ -1617,6 +1651,7 @@ async function setup(context: vscode.ExtensionContext, progress?: ProgressHandle 'setDefaultTarget', 'resetState', 'viewLog', + 'logDiagnostics', 'compileFile', 'selectWorkspace', 'tasksBuildCommand', diff --git a/src/folders.ts b/src/folders.ts index 93a07eddb..31ba8e469 100644 --- a/src/folders.ts +++ b/src/folders.ts @@ -11,10 +11,26 @@ import { KitsController } from '@cmt/kitsController'; import rollbar from '@cmt/rollbar'; import { disposeAll, setContextValue } from '@cmt/util'; import { PresetsController } from '@cmt/presetsController'; +import { CMakeCommunicationMode, UseCMakePresets } from './config'; nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })(); const localize: nls.LocalizeFunc = nls.loadMessageBundle(); +export interface DiagnosticsConfiguration { + folder: string; + cmakeVersion: string; + compilers: {C?: string; CXX?: string}; + usesPresets: boolean; + generator: string; + configured: boolean; +} + +export interface DiagnosticsSettings { + communicationMode: CMakeCommunicationMode; + useCMakePresets: UseCMakePresets; + configureOnOpen: boolean | null; +} + export class CMakeToolsFolder { private _wasUsingCMakePresets: boolean | undefined; private _onDidOpenTextDocumentListener: vscode.Disposable | undefined; @@ -74,7 +90,9 @@ export class CMakeToolsFolder { return cmtFolder; } - get folder() { return this.cmakeTools.folder; } + get folder() { + return this.cmakeTools.folder; + } // Go through the decision tree here since there would be dependency issues if we do this in config.ts get useCMakePresets(): boolean { @@ -89,7 +107,46 @@ export class CMakeToolsFolder { return this.cmakeTools.workspaceContext.config.useCMakePresets === 'always'; } - get onUseCMakePresetsChanged() { return this._onUseCMakePresetsChangedEmitter.event; } + async getDiagnostics(): Promise { + try { + const drv = await this.cmakeTools.getCMakeDriverInstance(); + if (drv) { + return drv.getDiagnostics(); + } + } catch { + } + return { + folder: this.folder.name, + cmakeVersion: "unknown", + configured: false, + generator: "unknown", + usesPresets: false, + compilers: {} + }; + } + + async getSettingsDiagnostics(): Promise { + try { + const drv = await this.cmakeTools.getCMakeDriverInstance(); + if (drv) { + return { + communicationMode: drv.config.cmakeCommunicationMode, + useCMakePresets: drv.config.useCMakePresets, + configureOnOpen: drv.config.configureOnOpen + }; + } + } catch { + } + return { + communicationMode: 'automatic', + useCMakePresets: 'auto', + configureOnOpen: null + }; + } + + get onUseCMakePresetsChanged() { + return this._onUseCMakePresetsChangedEmitter.event; + } dispose() { if (this._onDidOpenTextDocumentListener) { @@ -192,6 +249,10 @@ export class CMakeToolsFolderController implements vscode.Disposable { return undefined; } + getAll(): CMakeToolsFolder[] { + return [...this._instances.values()]; + } + /** * Load all the folders currently open in VSCode */