@@ -78,6 +78,7 @@ export interface Configuration {
7878}
7979
8080export interface ConfigurationErrors {
81+ name ?: string ;
8182 compilerPath ?: string ;
8283 includePath ?: string ;
8384 intelliSenseMode ?: string ;
@@ -1145,6 +1146,9 @@ export class CppProperties {
11451146 const isWindows : boolean = os . platform ( ) === 'win32' ;
11461147 const config : Configuration = this . configurationJson . configurations [ configIndex ] ;
11471148
1149+ // Check if config name is unique.
1150+ errors . name = this . isConfigNameUnique ( config . name ) ;
1151+
11481152 // Validate compilerPath
11491153 let resolvedCompilerPath : string | undefined = this . resolvePath ( config . compilerPath , isWindows ) ;
11501154 const compilerPathAndArgs : util . CompilerPathAndArgs = util . extractCompilerPathAndArgs ( resolvedCompilerPath ) ;
@@ -1293,6 +1297,15 @@ export class CppProperties {
12931297 return errorMsg ;
12941298 }
12951299
1300+ private isConfigNameUnique ( configName : string ) : string | undefined {
1301+ let errorMsg : string | undefined ;
1302+ const occurrences : number | undefined = this . ConfigurationNames ?. filter ( function ( name ) : boolean { return name === configName ; } ) . length ;
1303+ if ( occurrences ) {
1304+ errorMsg = localize ( 'duplicate.name' , "{0} is a duplicate. The configuration name should be unique." , configName ) ;
1305+ }
1306+ return errorMsg ;
1307+ }
1308+
12961309 private handleSquiggles ( ) : void {
12971310 if ( ! this . propertiesFile ) {
12981311 return ;
@@ -1334,8 +1347,49 @@ export class CppProperties {
13341347 envText = curText . substr ( envStart , envEnd ) ;
13351348 const envTextStartOffSet : number = envStart + 1 ;
13361349
1350+ // Check if all config names are unique.
1351+ let allConfigText : string = curText ;
1352+ let allConfigTextOffset : number = envTextStartOffSet ;
1353+ const nameRegex : RegExp = new RegExp ( `{\\s*"name"\\s*:\\s*".*"` ) ;
1354+ let configStart : number = allConfigText . search ( new RegExp ( nameRegex ) ) ;
1355+ let configNameStart : number ;
1356+ let configNameEnd : number ;
1357+ let configName : string ;
1358+ const configNames : Map < string , vscode . Range [ ] > = new Map < string , [ ] > ( ) ;
1359+ let dupErrorMsg : string ;
1360+ while ( configStart !== - 1 ) {
1361+ allConfigText = allConfigText . substr ( configStart ) ;
1362+ allConfigTextOffset += configStart ;
1363+ configNameStart = allConfigText . indexOf ( '"' , allConfigText . indexOf ( ':' ) + 1 ) + 1 ;
1364+ configNameEnd = allConfigText . indexOf ( '"' , configNameStart ) ;
1365+ configName = allConfigText . substr ( configNameStart , configNameEnd - configNameStart ) ;
1366+ const newRange : vscode . Range = new vscode . Range ( 0 , allConfigTextOffset + configNameStart , 0 , allConfigTextOffset + configNameEnd ) ;
1367+ const allRanges : vscode . Range [ ] | undefined = configNames . get ( configName ) ;
1368+ if ( allRanges ) {
1369+ allRanges . push ( newRange ) ;
1370+ configNames . set ( configName , allRanges ) ;
1371+ } else {
1372+ configNames . set ( configName , [ newRange ] ) ;
1373+ }
1374+ allConfigText = allConfigText . substr ( configNameEnd + 1 ) ;
1375+ allConfigTextOffset += configNameEnd + 1 ;
1376+ configStart = allConfigText . search ( new RegExp ( nameRegex ) ) ;
1377+ }
1378+ for ( const [ configName , allRanges ] of configNames ) {
1379+ if ( allRanges && allRanges . length > 1 ) {
1380+ dupErrorMsg = localize ( 'duplicate.name' , "{0} is a duplicate. The configuration name should be unique." , configName ) ;
1381+ allRanges . forEach ( nameRange => {
1382+ const diagnostic : vscode . Diagnostic = new vscode . Diagnostic (
1383+ new vscode . Range ( document . positionAt ( nameRange . start . character ) ,
1384+ document . positionAt ( nameRange . end . character ) ) ,
1385+ dupErrorMsg , vscode . DiagnosticSeverity . Warning ) ;
1386+ diagnostics . push ( diagnostic ) ;
1387+ } ) ;
1388+ }
1389+ }
1390+
13371391 // Get current config text
1338- const configStart : number = curText . search ( new RegExp ( `{\\s*"name"\\s*:\\s*"${ escapeStringRegExp ( currentConfiguration . name ) } "` ) ) ;
1392+ configStart = curText . search ( new RegExp ( `{\\s*"name"\\s*:\\s*"${ escapeStringRegExp ( currentConfiguration . name ) } "` ) ) ;
13391393 if ( configStart === - 1 ) {
13401394 telemetry . logLanguageServerEvent ( "ConfigSquiggles" , { "error" : "config name not first" } ) ;
13411395 return ;
0 commit comments