Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Extension/src/LanguageServer/clangTidyDocumentation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */

/**
* The clang-tidy documentation is published per major LLVM release, so a check's page lives
* under the .1.0 release of the major the binary in use comes from: 23.1.0 and 22.1.0 have
* pages, 23.1.1 and 22.1.3 do not. Checks added in a newer major have no page in an older one,
* so the URL follows the binary in use rather than the release bundled with the extension.
* When the version in use could not be determined, fall back to the bundled release.
*/
export const fallbackClangTidyDocVersion: string = '23.1.0';

const versionPattern: RegExp = /^([0-9]+)\.[0-9]+\.[0-9]+$/;

/** The release a clang-tidy version's documentation was published under. */
function documentationRelease(clangTidyVersion: string): string | undefined {
const match: RegExpMatchArray | null = clangTidyVersion.match(versionPattern);
return match ? `${match[1]}.1.0` : undefined;
}

export function getClangTidyDocumentationUrl(docPage: string, clangTidyVersion?: string): string {
const release: string | undefined = clangTidyVersion ? documentationRelease(clangTidyVersion) : undefined;
return `https://releases.llvm.org/${release ?? fallbackClangTidyDocVersion}/tools/clang/tools/extra/docs/clang-tidy/${docPage}`;
}
4 changes: 2 additions & 2 deletions Extension/src/LanguageServer/codeAnalysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import * as vscode from 'vscode';
import { NotificationType, Range } from 'vscode-languageclient';
import * as nls from 'vscode-nls';
import { getClangTidyDocumentationUrl } from './clangTidyDocumentation';
import { Location, WorkspaceEdit } from './commonTypes';
import { CppSourceStr } from './extension';
import { LanguageClient } from './languageClient';
Expand Down Expand Up @@ -379,8 +380,7 @@ export function publishCodeAnalysisDiagnostics(params: PublishCodeAnalysisDiagno
const checksPage: string = dashIndex > 0 ? primaryCode.substring(dashIndex + 1) : primaryCode;
docPage = `checks${checksGroup}/${checksPage}.html`;
}
// TODO: This should be checking the clang-tidy version used to better support usage of older versions.
const primaryDocUri: vscode.Uri = vscode.Uri.parse(`https://releases.llvm.org/23.1.0/tools/clang/tools/extra/docs/clang-tidy/${docPage}`);
const primaryDocUri: vscode.Uri = vscode.Uri.parse(getClangTidyDocumentationUrl(docPage, new CppSettings(realUri).clangTidyVersion));
diagnostic.code = { value: identifier.code, target: primaryDocUri };

if (new CppSettings().clangTidyCodeActionShowDocumentation) {
Expand Down
19 changes: 18 additions & 1 deletion Extension/src/LanguageServer/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import * as which from 'which';
import * as util from '../common';
import { getCachedClangFormatPath, getCachedClangTidyPath, getExtensionFilePath, getRawSetting, isArray, isArrayOfString, isBoolean, isNumber, isObject, isString, isValidMapping, setCachedClangFormatPath, setCachedClangTidyPath } from '../common';
import { getCachedClangFormatPath, getCachedClangTidyPath, getCachedClangTidyVersion, getExtensionFilePath, getRawSetting, isArray, isArrayOfString, isBoolean, isNumber, isObject, isString, isValidMapping, setCachedClangFormatPath, setCachedClangTidyPath, setCachedClangTidyVersion } from '../common';
import { isWindows } from '../constants';
import * as telemetry from '../telemetry';
import { cachedEditorConfigLookups, DefaultClient, hasTrustedCompilerPaths } from './client';
Expand Down Expand Up @@ -279,6 +279,14 @@ export class CppSettings extends Settings {
return this.getClangPath(false);
}

public get clangTidyVersion(): string | undefined {
// The cached version comes from an auto-discovered binary, so it says nothing about the
// clang-tidy a resource carrying its own path is running. Reporting it would point that
// resource's documentation links at the wrong release, so leave the version unknown and
// let the caller fall back.
return changeBlankStringToUndefined(this.getAsStringOrUndefined("codeAnalysis.clangTidy.path")) ? undefined : getCachedClangTidyVersion();
}

public get clangFormatPath(): string | undefined {
return this.getClangPath(true);
}
Expand All @@ -303,6 +311,7 @@ export class CppSettings extends Settings {
} else {
// Attempt to invoke both our own version of clang-* to see if we can successfully execute it, and to get its version.
let bundledVersion: string;
let clangVersion: string | undefined;
try {
const bundledPath: string = getExtensionFilePath(`./LLVM/bin/${clangName}`);
const output: string = execFileSync(bundledPath, ['--version']).toString();
Expand All @@ -322,10 +331,18 @@ export class CppSettings extends Settings {
if (semver.ltr(userVersion, bundledVersion)) {
path = "";
setCachedClangPath(path);
clangVersion = bundledVersion;
} else {
clangVersion = userVersion;
}
} catch {
path = "";
setCachedClangPath(path);
clangVersion = bundledVersion;
}

if (!isFormat && clangVersion) {
setCachedClangTidyVersion(clangVersion);
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions Extension/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ export function setCachedClangTidyPath(path: string): void {
cachedClangTidyPath = path;
}

let cachedClangTidyVersion: string | undefined;
export function getCachedClangTidyVersion(): string | undefined {
return cachedClangTidyVersion;
}

export function setCachedClangTidyVersion(version: string): void {
cachedClangTidyVersion = version;
}

// Use this package.json to read values
export const packageJson: any = vscode.extensions.getExtension("ms-vscode.cpptools")?.packageJSON;

Expand Down
33 changes: 33 additions & 0 deletions Extension/test/unit/clangTidyDocumentation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */

import { describe, it } from 'mocha';
import { strictEqual } from 'node:assert';
import { fallbackClangTidyDocVersion, getClangTidyDocumentationUrl } from '../../src/LanguageServer/clangTidyDocumentation';

const bundledDocUrl: string = `https://releases.llvm.org/${fallbackClangTidyDocVersion}/tools/clang/tools/extra/docs/clang-tidy`;

describe('clang-tidy documentation URLs', () => {
it('points at the clang-tidy version in use', () => {
strictEqual(
getClangTidyDocumentationUrl('checks/readability/use-std-min-max.html', '19.1.0'),
'https://releases.llvm.org/19.1.0/tools/clang/tools/extra/docs/clang-tidy/checks/readability/use-std-min-max.html');
});

it('uses the .1.0 release of that major, since patch releases have no page', () => {
strictEqual(
getClangTidyDocumentationUrl('checks/readability/use-std-min-max.html', '23.1.1'),
'https://releases.llvm.org/23.1.0/tools/clang/tools/extra/docs/clang-tidy/checks/readability/use-std-min-max.html');
strictEqual(
getClangTidyDocumentationUrl('checks/misc/include-cleaner.html', '22.1.3'),
'https://releases.llvm.org/22.1.0/tools/clang/tools/extra/docs/clang-tidy/checks/misc/include-cleaner.html');
});

it('falls back to the bundled version when the version in use is unknown', () => {
strictEqual(getClangTidyDocumentationUrl('checks/misc/include-cleaner.html'), `${bundledDocUrl}/checks/misc/include-cleaner.html`);
strictEqual(getClangTidyDocumentationUrl('checks/misc/include-cleaner.html', ''), `${bundledDocUrl}/checks/misc/include-cleaner.html`);
strictEqual(getClangTidyDocumentationUrl('checks/misc/include-cleaner.html', '23.1'), `${bundledDocUrl}/checks/misc/include-cleaner.html`);
});
});
Loading