Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add wildcard support for includeDir #10388

Merged
merged 3 commits into from
Jun 27, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
85 changes: 50 additions & 35 deletions Extension/src/LanguageServer/configurations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { SettingsPanel } from './settingsPanel';
import * as os from 'os';
import escapeStringRegExp = require('escape-string-regexp');
import * as jsonc from 'comment-json';
import * as fastGlob from 'fast-glob';
import * as nls from 'vscode-nls';
import { setTimeout } from 'timers';
import * as which from 'which';
Expand Down Expand Up @@ -156,7 +157,6 @@ export class CppProperties {
private diagnosticCollection: vscode.DiagnosticCollection;
private prevSquiggleMetrics: Map<string, { [key: string]: number }> = new Map<string, { [key: string]: number }>();
private settingsPanel?: SettingsPanel;
private isWin32: boolean = os.platform() === "win32";

// Any time the default settings are parsed and assigned to `this.configurationJson`,
// we want to track when the default includes have been added to it.
Expand Down Expand Up @@ -588,7 +588,7 @@ export class CppProperties {
configuration.intelliSenseMode === "${default}") {
return "";
}
const resolvedCompilerPath: string = this.resolvePath(configuration.compilerPath, true);
const resolvedCompilerPath: string = this.resolvePath(configuration.compilerPath);
const settings: CppSettings = new CppSettings(this.rootUri);
const compilerPathAndArgs: util.CompilerPathAndArgs = util.extractCompilerPathAndArgs(!!settings.legacyCompilerArgsBehavior, resolvedCompilerPath);

Expand Down Expand Up @@ -735,16 +735,35 @@ export class CppProperties {
return result;
}

private resolveAndSplit(paths: string[] | undefined, defaultValue: string[] | undefined, env: Environment): string[] {
let result: string[] = [];
private resolveAndSplit(paths: string[] | undefined, defaultValue: string[] | undefined, env: Environment, glob = false): string[] {
const result: string[] = [];
if (paths) {
paths = this.resolveDefaults(paths, defaultValue);
paths.forEach(entry => {
const entries: string[] = util.resolveVariables(entry, env).split(util.envDelimiter).filter(e => e);
result = result.concat(entries);
const entries: string[] = util.resolveVariables(entry, env).split(util.envDelimiter).map(e => this.resolvePath(e, false)).filter(e => e);
result.push(...entries);
});
}
return result;
if (!glob) {
return result;
}

const globResult: string[] = [];
for (let res of result) {
// fastGlob will expand the ending double wildcard. temporary strip them before expanding
const recursive: boolean = res.endsWith('**');
if (recursive) {
res = res.slice(0, res.length - 2);
}
// fastGlob can't deal with backslash-separated path => remove them
const normalized: string = res.replace(/\\/g, '/');
const cwd: string = this.rootUri?.fsPath?.replace(/\\/g, '/') || '';
// fastGlob silently strip non-found paths. limit that behavior to dynamic paths only
const matches: string[] = fastGlob.isDynamicPattern(normalized) ?
fastGlob.sync(normalized, { onlyDirectories: true, cwd}) : [res];
globResult.push(...matches.map(s => recursive ? s + '**' : s));
}
return globResult;
}

private updateConfigurationString(property: string | undefined | null, defaultValue: string | undefined | null, env: Environment, acceptBlank?: boolean): string | undefined {
Expand All @@ -769,10 +788,10 @@ export class CppProperties {

private updateConfigurationPathsArray(paths: string[] | undefined, defaultValue: string[] | undefined, env: Environment): string[] | undefined {
if (paths) {
return this.resolveAndSplit(paths, defaultValue, env);
return this.resolveAndSplit(paths, defaultValue, env, true);
}
if (!paths && defaultValue) {
return this.resolveAndSplit(defaultValue, [], env);
return this.resolveAndSplit(defaultValue, [], env, true);
}
return paths;
}
Expand Down Expand Up @@ -813,10 +832,8 @@ export class CppProperties {
}

private getDotconfigDefines(dotConfigPath: string): string[] {
const isWindows: boolean = os.platform() === 'win32';

if (dotConfigPath !== undefined) {
const path: string = this.resolvePath(dotConfigPath, isWindows);
const path: string = this.resolvePath(dotConfigPath);
try {
const configContent: string[] = fs.readFileSync(path, "utf-8").split("\n");
return configContent.filter(i => !i.startsWith("#") && i !== "");
Expand Down Expand Up @@ -847,7 +864,6 @@ export class CppProperties {
configuration.compilerPathInCppPropertiesJson = configuration.compilerPath;
configuration.compileCommandsInCppPropertiesJson = configuration.compileCommands;
configuration.configurationProviderInCppPropertiesJson = configuration.configurationProvider;

configuration.includePath = this.updateConfigurationPathsArray(configuration.includePath, settings.defaultIncludePath, env);
// in case includePath is reset below
const origIncludePath: string[] | undefined = configuration.includePath;
Expand Down Expand Up @@ -1014,23 +1030,23 @@ export class CppProperties {
* Ensure all paths are absolute
*/
if (configuration.macFrameworkPath) {
configuration.macFrameworkPath = configuration.macFrameworkPath.map((path: string) => this.resolvePath(path, this.isWin32));
configuration.macFrameworkPath = configuration.macFrameworkPath.map((path: string) => this.resolvePath(path));
}

if (configuration.dotConfig) {
configuration.dotConfig = this.resolvePath(configuration.dotConfig, this.isWin32);
configuration.dotConfig = this.resolvePath(configuration.dotConfig);
}

if (configuration.compileCommands) {
configuration.compileCommands = this.resolvePath(configuration.compileCommands, this.isWin32);
configuration.compileCommands = this.resolvePath(configuration.compileCommands);
}

if (configuration.forcedInclude) {
configuration.forcedInclude = configuration.forcedInclude.map((path: string) => this.resolvePath(path, this.isWin32));
configuration.forcedInclude = configuration.forcedInclude.map((path: string) => this.resolvePath(path));
}

if (configuration.includePath) {
configuration.includePath = configuration.includePath.map((path: string) => this.resolvePath(path, this.isWin32, false));
configuration.includePath = configuration.includePath.map((path: string) => this.resolvePath(path, false));
}
}

Expand All @@ -1052,7 +1068,7 @@ export class CppProperties {
const filePaths: Set<string> = new Set<string>();
this.configurationJson.configurations.forEach(c => {
if (c.compileCommands) {
const fileSystemCompileCommandsPath: string = this.resolvePath(c.compileCommands, this.isWin32);
const fileSystemCompileCommandsPath: string = this.resolvePath(c.compileCommands);
if (fs.existsSync(fileSystemCompileCommandsPath)) {
filePaths.add(fileSystemCompileCommandsPath);
}
Expand Down Expand Up @@ -1428,7 +1444,7 @@ export class CppProperties {
return success;
}

public resolvePath(input_path: string | undefined, isWindows: boolean, replaceAsterisks: boolean = true): string {
public resolvePath(input_path: string | undefined, replaceAsterisks: boolean = true): string {
if (!input_path || input_path === "${default}") {
return "";
}
Expand Down Expand Up @@ -1472,7 +1488,7 @@ export class CppProperties {
errors.name = this.isConfigNameUnique(config.name);

// Validate compilerPath
let resolvedCompilerPath: string | undefined = this.resolvePath(config.compilerPath, isWindows);
let resolvedCompilerPath: string | undefined = this.resolvePath(config.compilerPath);
const settings: CppSettings = new CppSettings(this.rootUri);
const compilerPathAndArgs: util.CompilerPathAndArgs = util.extractCompilerPathAndArgs(!!settings.legacyCompilerArgsBehavior, resolvedCompilerPath);
if (resolvedCompilerPath
Expand Down Expand Up @@ -1537,15 +1553,15 @@ export class CppProperties {
}

// Validate paths (directories)
errors.includePath = this.validatePath(config.includePath);
errors.includePath = this.validatePath(config.includePath, {globPaths: true});
errors.macFrameworkPath = this.validatePath(config.macFrameworkPath);
errors.browsePath = this.validatePath(config.browse ? config.browse.path : undefined);

// Validate files
errors.forcedInclude = this.validatePath(config.forcedInclude, false, true);
errors.compileCommands = this.validatePath(config.compileCommands, false);
errors.dotConfig = this.validatePath(config.dotConfig, false);
errors.databaseFilename = this.validatePath((config.browse ? config.browse.databaseFilename : undefined), false);
errors.forcedInclude = this.validatePath(config.forcedInclude, {isDirectory: false, skipRelativePaths: true});
errors.compileCommands = this.validatePath(config.compileCommands, {isDirectory: false});
errors.dotConfig = this.validatePath(config.dotConfig, {isDirectory: false});
errors.databaseFilename = this.validatePath((config.browse ? config.browse.databaseFilename : undefined), {isDirectory: false});

// Validate intelliSenseMode
if (isWindows) {
Expand All @@ -1558,12 +1574,11 @@ export class CppProperties {
return errors;
}

private validatePath(input: string | string[] | undefined, isDirectory: boolean = true, skipRelativePaths: boolean = false): string | undefined {
private validatePath(input: string | string[] | undefined, {isDirectory = true, skipRelativePaths = false, globPaths = false} = {}): string | undefined {
if (!input) {
return undefined;
}

const isWindows: boolean = os.platform() === 'win32';
let errorMsg: string | undefined;
const errors: string[] = [];
let paths: string[] = [];
Expand All @@ -1575,11 +1590,11 @@ export class CppProperties {
}

// Resolve and split any environment variables
paths = this.resolveAndSplit(paths, undefined, this.ExtendedEnvironment);
paths = this.resolveAndSplit(paths, undefined, this.ExtendedEnvironment, globPaths);

for (const p of paths) {
let pathExists: boolean = true;
let resolvedPath: string = this.resolvePath(p, isWindows);
let resolvedPath: string = this.resolvePath(p);
if (!resolvedPath) {
continue;
}
Expand Down Expand Up @@ -1785,7 +1800,7 @@ export class CppProperties {
// Skip the relative forcedInclude files.
if (currentConfiguration.forcedInclude) {
for (const file of currentConfiguration.forcedInclude) {
const resolvedFilePath: string = this.resolvePath(file, isWindows);
const resolvedFilePath: string = this.resolvePath(file);
if (path.isAbsolute(resolvedFilePath)) {
paths.push(`${file}`);
}
Expand All @@ -1803,7 +1818,7 @@ export class CppProperties {
// Resolve and split any environment variables
paths = this.resolveAndSplit(paths, undefined, this.ExtendedEnvironment);
compilerPath = util.resolveVariables(compilerPath, this.ExtendedEnvironment).trim();
compilerPath = this.resolvePath(compilerPath, isWindows);
compilerPath = this.resolvePath(compilerPath);

// Get the start/end for properties that are file-only.
const forcedIncludeStart: number = curText.search(/\s*\"forcedInclude\"\s*:\s*\[/);
Expand Down Expand Up @@ -1867,7 +1882,7 @@ export class CppProperties {

dotConfigPath = currentConfiguration.dotConfig;
dotConfigPath = util.resolveVariables(dotConfigPath, this.ExtendedEnvironment).trim();
dotConfigPath = this.resolvePath(dotConfigPath, isWindows);
dotConfigPath = this.resolvePath(dotConfigPath);
// does not try resolve if the dotConfig property is empty
dotConfigPath = dotConfigPath !== '' ? dotConfigPath : undefined;

Expand Down Expand Up @@ -1906,7 +1921,7 @@ export class CppProperties {
continue;
}

let resolvedPath: string = this.resolvePath(curPath, isWindows);
let resolvedPath: string = this.resolvePath(curPath);
if (!resolvedPath) {
continue;
}
Expand Down Expand Up @@ -2148,7 +2163,7 @@ export class CppProperties {
if (!compileCommands) {
return;
}
const compileCommandsFile: string | undefined = this.resolvePath(compileCommands, this.isWin32);
const compileCommandsFile: string | undefined = this.resolvePath(compileCommands);
fs.stat(compileCommandsFile, (err, stats) => {
if (err) {
if (err.code === "ENOENT" && this.compileCommandsFile) {
Expand Down