@@ -1838,9 +1838,9 @@ export class CppProperties {
18381838 curText = curText . substring ( 0 , nextNameStart2 ) ;
18391839 }
18401840 if ( this . prevSquiggleMetrics . get ( currentConfiguration . name ) === undefined ) {
1841- this . prevSquiggleMetrics . set ( currentConfiguration . name , { PathNonExistent : 0 , PathNotAFile : 0 , PathNotADirectory : 0 , CompilerPathMissingQuotes : 0 , CompilerModeMismatch : 0 } ) ;
1841+ this . prevSquiggleMetrics . set ( currentConfiguration . name , { PathNonExistent : 0 , PathNotAFile : 0 , PathNotADirectory : 0 , CompilerPathMissingQuotes : 0 , CompilerModeMismatch : 0 , MultiplePathsNotAllowed : 0 } ) ;
18421842 }
1843- const newSquiggleMetrics : { [ key : string ] : number } = { PathNonExistent : 0 , PathNotAFile : 0 , PathNotADirectory : 0 , CompilerPathMissingQuotes : 0 , CompilerModeMismatch : 0 } ;
1843+ const newSquiggleMetrics : { [ key : string ] : number } = { PathNonExistent : 0 , PathNotAFile : 0 , PathNotADirectory : 0 , CompilerPathMissingQuotes : 0 , CompilerModeMismatch : 0 , MultiplePathsNotAllowed : 0 } ;
18441844 const isWindows : boolean = os . platform ( ) === 'win32' ;
18451845
18461846 // TODO: Add other squiggles.
@@ -1867,7 +1867,7 @@ export class CppProperties {
18671867 }
18681868
18691869 // Check for path-related squiggles.
1870- let paths : string [ ] = [ ] ;
1870+ const paths : string [ ] = [ ] ;
18711871 let compilerPath : string | undefined ;
18721872 for ( const pathArray of [ currentConfiguration . browse ? currentConfiguration . browse . path : undefined ,
18731873 currentConfiguration . includePath , currentConfiguration . macFrameworkPath ] ) {
@@ -1895,10 +1895,7 @@ export class CppProperties {
18951895 compilerPath = currentConfiguration . compilerPath ;
18961896 }
18971897
1898- // Resolve and split any environment variables
1899- paths = this . resolveAndSplit ( paths , undefined , this . ExtendedEnvironment ) ;
1900- compilerPath = util . resolveVariables ( compilerPath , this . ExtendedEnvironment ) . trim ( ) ;
1901- compilerPath = this . resolvePath ( compilerPath ) ;
1898+ compilerPath = this . resolvePath ( compilerPath ) . trim ( ) ;
19021899
19031900 // Get the start/end for properties that are file-only.
19041901 const forcedIncludeStart : number = curText . search ( / \s * \" f o r c e d I n c l u d e \" \s * : \s * \[ / ) ;
@@ -1961,8 +1958,7 @@ export class CppProperties {
19611958 let dotConfigMessage : string | undefined ;
19621959
19631960 dotConfigPath = currentConfiguration . dotConfig ;
1964- dotConfigPath = util . resolveVariables ( dotConfigPath , this . ExtendedEnvironment ) . trim ( ) ;
1965- dotConfigPath = this . resolvePath ( dotConfigPath ) ;
1961+ dotConfigPath = this . resolvePath ( dotConfigPath ) . trim ( ) ;
19661962 // does not try resolve if the dotConfig property is empty
19671963 dotConfigPath = dotConfigPath !== '' ? dotConfigPath : undefined ;
19681964
@@ -2001,25 +1997,6 @@ export class CppProperties {
20011997 continue ;
20021998 }
20031999
2004- let resolvedPath : string = this . resolvePath ( curPath ) ;
2005- if ( ! resolvedPath ) {
2006- continue ;
2007- }
2008- let pathExists : boolean = true ;
2009- if ( this . rootUri ) {
2010- const checkPathExists : any = util . checkPathExistsSync ( resolvedPath , this . rootUri . fsPath + path . sep , isWindows , false ) ;
2011- pathExists = checkPathExists . pathExists ;
2012- resolvedPath = checkPathExists . path ;
2013- }
2014- // Normalize path separators.
2015- if ( path . sep === "/" ) {
2016- resolvedPath = resolvedPath . replace ( / \\ / g, path . sep ) ;
2017- } else {
2018- resolvedPath = resolvedPath . replace ( / \/ / g, path . sep ) ;
2019- }
2020-
2021- // Iterate through the text and apply squiggles.
2022-
20232000 // Escape the path string for literal use in a regular expression
20242001 // Need to escape any quotes to match the original text
20252002 let escapedPath : string = curPath . replace ( / " / g, '\\"' ) ;
@@ -2030,6 +2007,42 @@ export class CppProperties {
20302007 const pattern : RegExp = new RegExp ( `"[^"]*?(?<="|;)${ escapedPath } (?="|;).*?"` , "g" ) ;
20312008 const configMatches : string [ ] | null = curText . match ( pattern ) ;
20322009
2010+ const expandedPaths : string [ ] = this . resolveAndSplit ( [ curPath ] , undefined , this . ExtendedEnvironment , true , true ) ;
2011+ const incorrectExpandedPaths : string [ ] = [ ] ;
2012+
2013+ if ( expandedPaths . length <= 0 ) {
2014+ continue ;
2015+ }
2016+
2017+ if ( this . rootUri ) {
2018+ for ( const [ index , expandedPath ] of expandedPaths . entries ( ) ) {
2019+ if ( expandedPath . includes ( "${workspaceFolder}" ) ) {
2020+ expandedPaths [ index ] = this . resolvePath ( expandedPath , false ) ;
2021+ } else {
2022+ expandedPaths [ index ] = this . resolvePath ( expandedPath ) ;
2023+ }
2024+
2025+ const checkPathExists : any = util . checkPathExistsSync ( expandedPaths [ index ] , this . rootUri . fsPath + path . sep , isWindows , false ) ;
2026+ if ( ! checkPathExists . pathExists ) {
2027+ // If there are multiple paths, store any non-existing paths to squiggle later on.
2028+ incorrectExpandedPaths . push ( expandedPaths [ index ] ) ;
2029+ }
2030+ }
2031+ }
2032+
2033+ const pathExists : boolean = incorrectExpandedPaths . length === 0 ;
2034+
2035+ for ( const [ index , expandedPath ] of expandedPaths . entries ( ) ) {
2036+ // Normalize path separators.
2037+ if ( path . sep === "/" ) {
2038+ expandedPaths [ index ] = expandedPath . replace ( / \\ / g, path . sep ) ;
2039+ } else {
2040+ expandedPaths [ index ] = expandedPath . replace ( / \/ / g, path . sep ) ;
2041+ }
2042+ }
2043+
2044+ // Iterate through the text and apply squiggles.
2045+
20332046 let globPath : boolean = false ;
20342047 const asteriskPosition = curPath . indexOf ( "*" ) ;
20352048 if ( asteriskPosition !== - 1 ) {
@@ -2041,6 +2054,7 @@ export class CppProperties {
20412054 }
20422055 }
20432056 }
2057+
20442058 if ( configMatches && ! globPath ) {
20452059 let curOffset : number = 0 ;
20462060 let endOffset : number = 0 ;
@@ -2050,29 +2064,57 @@ export class CppProperties {
20502064 if ( curOffset >= compilerPathStart && curOffset <= compilerPathEnd ) {
20512065 continue ;
20522066 }
2053- let message : string ;
2067+ let message : string = "" ;
20542068 if ( ! pathExists ) {
20552069 if ( curOffset >= forcedIncludeStart && curOffset <= forcedeIncludeEnd
2056- && ! path . isAbsolute ( resolvedPath ) ) {
2070+ && ! path . isAbsolute ( expandedPaths [ 0 ] ) ) {
20572071 continue ; // Skip the error, because it could be resolved recursively.
20582072 }
2059- message = localize ( 'cannot.find2' , "Cannot find \"{0}\"." , resolvedPath ) ;
2073+ let badPath = "" ;
2074+ if ( incorrectExpandedPaths . length > 0 ) {
2075+ badPath = incorrectExpandedPaths . map ( s => `"${ s } "` ) . join ( ', ' ) ;
2076+ } else {
2077+ badPath = `"${ expandedPaths [ 0 ] } "` ;
2078+ }
2079+ message = localize ( 'cannot.find2' , "Cannot find {0}" , badPath ) ;
20602080 newSquiggleMetrics . PathNonExistent ++ ;
20612081 } else {
20622082 // Check for file versus path mismatches.
20632083 if ( ( curOffset >= forcedIncludeStart && curOffset <= forcedeIncludeEnd ) ||
2064- ( curOffset >= compileCommandsStart && curOffset <= compileCommandsEnd ) ) {
2065- if ( util . checkFileExistsSync ( resolvedPath ) ) {
2066- continue ;
2084+ ( curOffset >= compileCommandsStart && curOffset <= compileCommandsEnd ) ) {
2085+ if ( expandedPaths . length > 1 ) {
2086+ message = localize ( "multiple.paths.not.allowed" , "Multiple paths are not allowed." ) ;
2087+ newSquiggleMetrics . MultiplePathsNotAllowed ++ ;
2088+ } else {
2089+ const resolvedPath = this . resolvePath ( expandedPaths [ 0 ] ) ;
2090+ if ( util . checkFileExistsSync ( resolvedPath ) ) {
2091+ continue ;
2092+ }
2093+
2094+ message = localize ( "path.is.not.a.file" , "Path is not a file: {0}" , expandedPaths [ 0 ] ) ;
2095+ newSquiggleMetrics . PathNotAFile ++ ;
20672096 }
2068- message = localize ( "path.is.not.a.file" , "Path is not a file: {0}" , resolvedPath ) ;
2069- newSquiggleMetrics . PathNotAFile ++ ;
20702097 } else {
2071- if ( util . checkDirectoryExistsSync ( resolvedPath ) ) {
2098+ const mismatchedPaths : string [ ] = [ ] ;
2099+ for ( const expandedPath of expandedPaths ) {
2100+ const resolvedPath = this . resolvePath ( expandedPath ) ;
2101+ if ( ! util . checkDirectoryExistsSync ( resolvedPath ) ) {
2102+ mismatchedPaths . push ( expandedPath ) ;
2103+ }
2104+ }
2105+
2106+ let badPath = "" ;
2107+ if ( mismatchedPaths . length > 1 ) {
2108+ badPath = mismatchedPaths . map ( s => `"${ s } "` ) . join ( ', ' ) ;
2109+ message = localize ( 'paths.are.not.directories' , "Paths are not directories: {0}" , badPath ) ;
2110+ newSquiggleMetrics . PathNotADirectory ++ ;
2111+ } else if ( mismatchedPaths . length === 1 ) {
2112+ badPath = `"${ mismatchedPaths [ 0 ] } "` ;
2113+ message = localize ( 'path.is.not.a.directory' , "Path is not a directory: {0}" , badPath ) ;
2114+ newSquiggleMetrics . PathNotADirectory ++ ;
2115+ } else {
20722116 continue ;
20732117 }
2074- message = localize ( "path.is.not.a.directory" , "Path is not a directory: {0}" , resolvedPath ) ;
2075- newSquiggleMetrics . PathNotADirectory ++ ;
20762118 }
20772119 }
20782120 const diagnostic : vscode . Diagnostic = new vscode . Diagnostic (
@@ -2092,7 +2134,7 @@ export class CppProperties {
20922134 endOffset = curOffset + curMatch . length ;
20932135 let message : string ;
20942136 if ( ! pathExists ) {
2095- message = localize ( 'cannot.find2' , "Cannot find \"{0}\"." , resolvedPath ) ;
2137+ message = localize ( 'cannot.find2' , "Cannot find \"{0}\"." , expandedPaths [ 0 ] ) ;
20962138 newSquiggleMetrics . PathNonExistent ++ ;
20972139 const diagnostic : vscode . Diagnostic = new vscode . Diagnostic (
20982140 new vscode . Range ( document . positionAt ( envTextStartOffSet + curOffset ) ,
@@ -2128,6 +2170,9 @@ export class CppProperties {
21282170 if ( newSquiggleMetrics . CompilerModeMismatch !== this . prevSquiggleMetrics . get ( currentConfiguration . name ) ?. CompilerModeMismatch ) {
21292171 changedSquiggleMetrics . CompilerModeMismatch = newSquiggleMetrics . CompilerModeMismatch ;
21302172 }
2173+ if ( newSquiggleMetrics . MultiplePathsNotAllowed !== this . prevSquiggleMetrics . get ( currentConfiguration . name ) ?. MultiplePathsNotAllowed ) {
2174+ changedSquiggleMetrics . MultiplePathsNotAllowed = newSquiggleMetrics . MultiplePathsNotAllowed ;
2175+ }
21312176 if ( Object . keys ( changedSquiggleMetrics ) . length > 0 ) {
21322177 telemetry . logLanguageServerEvent ( "ConfigSquiggles" , undefined , changedSquiggleMetrics ) ;
21332178 }
0 commit comments