Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7f4fc33

Browse files
michelleangelasean-mcmanus
authored andcommitted
Add input validation on configuration UI (microsoft#3563)
* show errors on config UI
1 parent788cee3 commit7f4fc33

File tree

4 files changed

+245
-78
lines changed

4 files changed

+245
-78
lines changed

‎Extension/src/LanguageServer/configurations.ts‎

Lines changed: 172 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ export interface Configuration {
6464
browse?:Browse;
6565
}
6666

67+
exportinterfaceConfigurationErrors{
68+
compilerPath?:string;
69+
includePath?:string;
70+
intelliSenseMode?:string;
71+
}
72+
6773
exportinterfaceBrowse{
6874
path?:string[];
6975
limitSymbolsToIncludedHeaders?:boolean|string;
@@ -227,7 +233,9 @@ export class CppProperties {
227233
// Clear out any modifications we may have made internally by parsing the json file
228234
if(this.parsePropertiesFile(false)){
229235
// Update the UI with new selected configuration
230-
this.settingsPanel.updateConfigUI(this.configurationJson.configurations[this.currentConfigurationIndex.Value]);
236+
this.settingsPanel.updateConfigUI(
237+
this.configurationJson.configurations[this.currentConfigurationIndex.Value],
238+
this.getErrorsForConfigUI());
231239
}else{
232240
// Parse failed, open json file
233241
vscode.workspace.openTextDocument(this.propertiesFile);
@@ -392,8 +400,13 @@ export class CppProperties {
392400
privateisCompilerIntelliSenseModeCompatible():boolean{
393401
// Check if intelliSenseMode and compilerPath are compatible
394402
// cl.exe and msvc mode should be used together
395-
// Ignore if compiler path is not set
396-
if(this.CurrentConfiguration.compilerPath===undefined){
403+
// Ignore if compiler path is not set or intelliSenseMode is not set
404+
if(this.CurrentConfiguration.compilerPath===undefined||
405+
this.CurrentConfiguration.compilerPath===""||
406+
this.CurrentConfiguration.compilerPath==="${default}"||
407+
this.CurrentConfiguration.intelliSenseMode===undefined||
408+
this.CurrentConfiguration.intelliSenseMode===""||
409+
this.CurrentConfiguration.intelliSenseMode==="${default}"){
397410
returntrue;
398411
}
399412
letcompilerPathAndArgs:util.CompilerPathAndArgs=util.extractCompilerPathAndArgs(this.CurrentConfiguration.compilerPath);
@@ -628,7 +641,9 @@ export class CppProperties {
628641
this.settingsPanel.ConfigValuesChanged(()=>this.saveConfigurationUI());
629642
this.disposables.push(this.settingsPanel);
630643
}
631-
this.settingsPanel.createOrShow(this.configurationJson.configurations[this.currentConfigurationIndex.Value]);
644+
this.settingsPanel.createOrShow(
645+
this.configurationJson.configurations[this.currentConfigurationIndex.Value],
646+
this.getErrorsForConfigUI());
632647
}else{
633648
// Parse failed, open json file
634649
vscode.workspace.openTextDocument(this.propertiesFile).then((document:vscode.TextDocument)=>{
@@ -646,7 +661,9 @@ export class CppProperties {
646661
if(this.parsePropertiesFile(false)){
647662
// The settings UI became visible or active.
648663
// Ensure settingsPanel has copy of latest current configuration
649-
this.settingsPanel.updateConfigUI(this.configurationJson.configurations[this.currentConfigurationIndex.Value]);
664+
this.settingsPanel.updateConfigUI(
665+
this.configurationJson.configurations[this.currentConfigurationIndex.Value],
666+
this.getErrorsForConfigUI());
650667
}else{
651668
// Parse failed, open json file
652669
vscode.workspace.openTextDocument(this.propertiesFile);
@@ -660,6 +677,7 @@ export class CppProperties {
660677
this.parsePropertiesFile(false);// Clear out any modifications we may have made internally.
661678
letconfig:Configuration=this.settingsPanel.getLastValuesFromConfigUI();
662679
this.configurationJson.configurations[this.currentConfigurationIndex.Value]=config;
680+
this.settingsPanel.updateErrors(this.getErrorsForConfigUI());
663681
this.writeToJson();
664682
}
665683

@@ -822,6 +840,150 @@ export class CppProperties {
822840
returnsuccess;
823841
}
824842

843+
privateresolvePath(path:string,isWindows:boolean):string{
844+
if(!path||path==="${default}"){
845+
return"";
846+
}
847+
848+
letresult:string="";
849+
850+
// first resolve variables
851+
result=util.resolveVariables(path,this.ExtendedEnvironment);
852+
if(result.includes("${workspaceFolder}")){
853+
result=result.replace("${workspaceFolder}",this.rootUri.fsPath);
854+
}
855+
if(result.includes("${workspaceRoot}")){
856+
result=result.replace("${workspaceRoot}",this.rootUri.fsPath);
857+
}
858+
if(result.includes("${vcpkgRoot}")&&util.getVcpkgRoot()){
859+
result=result.replace("${vcpkgRoot}",util.getVcpkgRoot());
860+
}
861+
if(result.includes("*")){
862+
result=result.replace(/\*/g,"");
863+
}
864+
865+
// resolve WSL paths
866+
if(isWindows&&result.startsWith("/")){
867+
constmntStr:string="/mnt/";
868+
if(result.length>"/mnt/c/".length&&result.substr(0,mntStr.length)===mntStr){
869+
result=result.substr(mntStr.length);
870+
result=result.substr(0,1)+":"+result.substr(1);
871+
}elseif(this.rootfs&&this.rootfs.length>0){
872+
result=this.rootfs+result.substr(1);
873+
// TODO: Handle WSL symlinks.
874+
}
875+
}
876+
877+
returnresult;
878+
}
879+
880+
privategetErrorsForConfigUI():ConfigurationErrors{
881+
leterrors:ConfigurationErrors={};
882+
constisWindows:boolean=os.platform()==='win32';
883+
884+
// Validate compilerPath
885+
letresolvedCompilerPath:string=this.resolvePath(this.CurrentConfiguration.compilerPath,isWindows);
886+
letcompilerPathAndArgs:util.CompilerPathAndArgs=util.extractCompilerPathAndArgs(resolvedCompilerPath);
887+
if(resolvedCompilerPath&&
888+
// Don't error cl.exe paths because it could be for an older preview build.
889+
!(isWindows&&compilerPathAndArgs.compilerPath.endsWith("cl.exe"))){
890+
resolvedCompilerPath=resolvedCompilerPath.trim();
891+
892+
// Error when the compiler's path has spaces without quotes but args are used.
893+
// Except, exclude cl.exe paths because it could be for an older preview build.
894+
letcompilerPathNeedsQuotes:boolean=
895+
compilerPathAndArgs.additionalArgs&&
896+
!resolvedCompilerPath.startsWith('"')&&
897+
compilerPathAndArgs.compilerPath.includes(" ");
898+
899+
letcompilerPathErrors:string[]=[];
900+
if(compilerPathNeedsQuotes){
901+
compilerPathErrors.push(`Compiler path with spaces and arguments is missing double quotes " around the path.`);
902+
}
903+
904+
// Get compiler path without arguments before checking if it exists
905+
resolvedCompilerPath=compilerPathAndArgs.compilerPath;
906+
907+
letpathExists:boolean=true;
908+
letexistsWithExeAdded:(path:string)=>boolean=(path:string)=>{
909+
returnisWindows&&!path.startsWith("/")&&fs.existsSync(path+".exe");
910+
};
911+
if(!fs.existsSync(resolvedCompilerPath)){
912+
if(existsWithExeAdded(resolvedCompilerPath)){
913+
resolvedCompilerPath+=".exe";
914+
}else{
915+
// Check again for a relative path.
916+
constrelativePath:string=this.rootUri.fsPath+path.sep+resolvedCompilerPath;
917+
if(!fs.existsSync(relativePath)){
918+
if(existsWithExeAdded(resolvedCompilerPath)){
919+
resolvedCompilerPath+=".exe";
920+
}else{
921+
pathExists=false;
922+
}
923+
}else{
924+
resolvedCompilerPath=relativePath;
925+
}
926+
}
927+
}
928+
929+
if(!pathExists){
930+
letmessage:string=`Cannot find:${resolvedCompilerPath}`;
931+
compilerPathErrors.push(message);
932+
}elseif(!util.checkFileExistsSync(resolvedCompilerPath)){
933+
letmessage:string=`Path is not a file:${resolvedCompilerPath}`;
934+
compilerPathErrors.push(message);
935+
}
936+
937+
if(compilerPathErrors.length>0){
938+
errors.compilerPath=compilerPathErrors.join('\n');
939+
}
940+
}
941+
942+
// Validate includePath
943+
letincludePathErrors:string[]=[];
944+
for(letincludePathofthis.CurrentConfiguration.includePath){
945+
letpathExists:boolean=true;
946+
letresolvedIncludePath:string=this.resolvePath(includePath,isWindows);
947+
if(!resolvedIncludePath){
948+
continue;
949+
}
950+
951+
// Check if resolved path exists
952+
if(!fs.existsSync(resolvedIncludePath)){
953+
// Check for relative path if resolved path does not exists
954+
constrelativePath:string=this.rootUri.fsPath+path.sep+resolvedIncludePath;
955+
if(!fs.existsSync(relativePath)){
956+
pathExists=false;
957+
}else{
958+
resolvedIncludePath=relativePath;
959+
}
960+
}
961+
962+
if(!pathExists){
963+
letmessage:string=`Cannot find:${resolvedIncludePath}`;
964+
includePathErrors.push(message);
965+
continue;
966+
}
967+
968+
// Check if path is a directory
969+
if(!util.checkDirectoryExistsSync(resolvedIncludePath)){
970+
letmessage:string=`Path is not a directory:${resolvedIncludePath}`;
971+
includePathErrors.push(message);
972+
}
973+
}
974+
975+
if(includePathErrors.length>0){
976+
errors.includePath=includePathErrors.join('\n');
977+
}
978+
979+
// Validate intelliSenseMode
980+
if(isWindows&&!this.isCompilerIntelliSenseModeCompatible()){
981+
errors.intelliSenseMode=`IntelliSense mode${this.CurrentConfiguration.intelliSenseMode} is incompatible with compiler path.`;
982+
}
983+
984+
returnerrors;
985+
}
986+
825987
privatehandleSquiggles():void{
826988
if(!this.propertiesFile){
827989
return;
@@ -926,35 +1088,14 @@ export class CppProperties {
9261088
// TODO: Add squiggles for when the C_Cpp.default.* paths are invalid.
9271089
continue;
9281090
}
929-
letresolvedPath:string=util.resolveVariables(curPath,this.ExtendedEnvironment);
930-
if(resolvedPath.includes("${workspaceFolder}")){
931-
resolvedPath=resolvedPath.replace("${workspaceFolder}",this.rootUri.fsPath);
932-
}
933-
if(resolvedPath.includes("${workspaceRoot}")){
934-
resolvedPath=resolvedPath.replace("${workspaceRoot}",this.rootUri.fsPath);
935-
}
936-
if(resolvedPath.includes("${vcpkgRoot}")){
937-
resolvedPath=resolvedPath.replace("${vcpkgRoot}",util.getVcpkgRoot());
938-
}
939-
if(resolvedPath.includes("*")){
940-
resolvedPath=resolvedPath.replace(/\*/g,"");
1091+
1092+
letresolvedPath:string=this.resolvePath(curPath,isWindows);
1093+
if(!resolvedPath){
1094+
continue;
9411095
}
9421096

9431097
// TODO: Invalid paths created from environment variables are not detected.
9441098

945-
// Handle WSL paths.
946-
constisWSL:boolean=isWindows&&resolvedPath.startsWith("/");
947-
if(isWSL){
948-
constmntStr:string="/mnt/";
949-
if(resolvedPath.length>"/mnt/c/".length&&resolvedPath.substr(0,mntStr.length)===mntStr){
950-
resolvedPath=resolvedPath.substr(mntStr.length);
951-
resolvedPath=resolvedPath.substr(0,1)+":"+resolvedPath.substr(1);
952-
}elseif(this.rootfs&&this.rootfs.length>0){
953-
resolvedPath=this.rootfs+resolvedPath.substr(1);
954-
// TODO: Handle WSL symlinks.
955-
}
956-
}
957-
9581099
letcompilerPathNeedsQuotes:boolean=false;
9591100
if(isCompilerPath){
9601101
resolvedPath=resolvedPath.trim();
@@ -967,6 +1108,7 @@ export class CppProperties {
9671108
resolvedPath=compilerPathAndArgs.compilerPath;
9681109
}
9691110

1111+
constisWSL:boolean=isWindows&&resolvedPath.startsWith("/");
9701112
letpathExists:boolean=true;
9711113
letexistsWithExeAdded:(path:string)=>boolean=(path:string)=>{
9721114
returnisCompilerPath&&isWindows&&!isWSL&&fs.existsSync(path+".exe");

‎Extension/src/LanguageServer/settingsPanel.ts‎

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export class SettingsPanel {
4040
);
4141
}
4242

43-
publiccreateOrShow(activeConfiguration:config.Configuration):void{
43+
publiccreateOrShow(activeConfiguration:config.Configuration,errors:config.ConfigurationErrors):void{
4444
constcolumn:vscode.ViewColumn=vscode.window.activeTextEditor
4545
?vscode.window.activeTextEditor.viewColumn
4646
:undefined;
@@ -80,7 +80,7 @@ export class SettingsPanel {
8080

8181
this.panel.webview.html=this.getHtml();
8282

83-
this.updateWebview(activeConfiguration);
83+
this.updateWebview(activeConfiguration,errors);
8484
}
8585

8686
publicgetSettingsPanelActivated():vscode.Event<void>{
@@ -95,18 +95,17 @@ export class SettingsPanel {
9595
returnthis.configValues;
9696
}
9797

98-
publicupdateConfigUI(configuration:config.Configuration):void{
98+
publicupdateConfigUI(configuration:config.Configuration,errors:config.ConfigurationErrors):void{
9999
if(this.panel){
100-
this.updateWebview(configuration);
100+
this.updateWebview(configuration,errors);
101101
}
102102
}
103103

104-
//TODO: validate input paths
105-
// public validatePaths(invalid: boolean) {
106-
// if (this.panel) {
107-
// this.panel.webview.postMessage({ command: 'validateCompilerPath', invalid: invalid });
108-
// }
109-
// }
104+
publicupdateErrors(errors:config.ConfigurationErrors):void{
105+
if(this.panel){
106+
this.panel.webview.postMessage({command:'updateErrors',errors:errors});
107+
}
108+
}
110109

111110
publicdispose():void{
112111
// Clean up resources
@@ -128,12 +127,13 @@ export class SettingsPanel {
128127
}
129128
}
130129

131-
privateupdateWebview(configuration:config.Configuration):void{
130+
privateupdateWebview(configuration:config.Configuration,errors:config.ConfigurationErrors):void{
132131
this.configValues=Object.assign({},configuration);// Copy configuration values
133132
this.isIntelliSenseModeDefined=(this.configValues.intelliSenseMode!==undefined);
134133
if(this.panel){
135-
// Send a message to the webview to update the values
136-
this.panel.webview.postMessage({command:'update',config:this.configValues});
134+
// Send a message to the webview to update the values and errors
135+
this.panel.webview.postMessage({command:'updateConfig',config:this.configValues});
136+
this.panel.webview.postMessage({command:'updateErrors',errors:errors});
137137
}
138138
}
139139

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp