Skip to content

Commit 90999e4

Browse files
authored
Fix CodeLens crash when a file cannot be opened, stop unnecessary file reads in CodeLens (#732)
* [Style] Refactor FindReferencesOfSymbol code * Check that file exists before parsing for symbols * Fix unnecessary file read for workspace script files
1 parent cb20e45 commit 90999e4

File tree

1 file changed

+73
-55
lines changed

1 file changed

+73
-55
lines changed

src/PowerShellEditorServices/Language/LanguageService.cs

+73-55
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
using System;
99
using System.Collections.Generic;
1010
using System.Collections.Specialized;
11+
using System.IO;
1112
using System.Linq;
1213
using System.Management.Automation;
1314
using System.Management.Automation.Language;
15+
using System.Runtime.InteropServices;
1416
using System.Threading;
1517
using System.Threading.Tasks;
1618

@@ -294,72 +296,88 @@ public async Task<FindReferencesResult> FindReferencesOfSymbol(
294296
ScriptFile[] referencedFiles,
295297
Workspace workspace)
296298
{
297-
if (foundSymbol != null)
299+
if (foundSymbol == null)
298300
{
299-
int symbolOffset = referencedFiles[0].GetOffsetAtPosition(
300-
foundSymbol.ScriptRegion.StartLineNumber,
301-
foundSymbol.ScriptRegion.StartColumnNumber);
302-
303-
// Make sure aliases have been loaded
304-
await GetAliases();
301+
return null;
302+
}
305303

306-
// We want to look for references first in referenced files, hence we use ordered dictionary
307-
var fileMap = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
308-
foreach (ScriptFile file in referencedFiles)
309-
{
310-
fileMap.Add(file.FilePath, file);
311-
}
304+
int symbolOffset = referencedFiles[0].GetOffsetAtPosition(
305+
foundSymbol.ScriptRegion.StartLineNumber,
306+
foundSymbol.ScriptRegion.StartColumnNumber);
307+
308+
// Make sure aliases have been loaded
309+
await GetAliases();
310+
311+
// We want to look for references first in referenced files, hence we use ordered dictionary
312+
// TODO: File system case-sensitivity is based on filesystem not OS, but OS is a much cheaper heuristic
313+
#if CoreCLR
314+
// The RuntimeInformation.IsOSPlatform is not supported in .NET Framework
315+
var fileMap = RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
316+
? new OrderedDictionary()
317+
: new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
318+
#else
319+
var fileMap = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
320+
#endif
321+
foreach (ScriptFile file in referencedFiles)
322+
{
323+
fileMap.Add(file.FilePath, file);
324+
}
312325

313-
var allFiles = workspace.EnumeratePSFiles();
314-
foreach (var file in allFiles)
326+
foreach (string file in workspace.EnumeratePSFiles())
327+
{
328+
if (!fileMap.Contains(file))
315329
{
316-
if (!fileMap.Contains(file))
330+
ScriptFile scriptFile;
331+
try
317332
{
318-
fileMap.Add(file, new ScriptFile(file, null, this.powerShellContext.LocalPowerShellVersion.Version));
333+
scriptFile = workspace.GetFile(file);
319334
}
335+
catch (IOException)
336+
{
337+
// If the file has ceased to exist for some reason, we just skip it
338+
continue;
339+
}
340+
341+
fileMap.Add(file, scriptFile);
320342
}
343+
}
321344

322-
List<SymbolReference> symbolReferences = new List<SymbolReference>();
323-
foreach (var fileName in fileMap.Keys)
324-
{
325-
var file = (ScriptFile)fileMap[fileName];
326-
IEnumerable<SymbolReference> symbolReferencesinFile =
327-
AstOperations
328-
.FindReferencesOfSymbol(
329-
file.ScriptAst,
330-
foundSymbol,
331-
CmdletToAliasDictionary,
332-
AliasToCmdletDictionary)
333-
.Select(
334-
reference =>
345+
var symbolReferences = new List<SymbolReference>();
346+
foreach (object fileName in fileMap.Keys)
347+
{
348+
var file = (ScriptFile)fileMap[fileName];
349+
IEnumerable<SymbolReference> symbolReferencesinFile =
350+
AstOperations
351+
.FindReferencesOfSymbol(
352+
file.ScriptAst,
353+
foundSymbol,
354+
CmdletToAliasDictionary,
355+
AliasToCmdletDictionary)
356+
.Select(reference =>
357+
{
358+
try
335359
{
336-
try
337-
{
338-
reference.SourceLine =
339-
file.GetLine(reference.ScriptRegion.StartLineNumber);
340-
}
341-
catch (ArgumentOutOfRangeException e)
342-
{
343-
reference.SourceLine = string.Empty;
344-
this.logger.WriteException("Found reference is out of range in script file", e);
345-
}
346-
347-
reference.FilePath = file.FilePath;
348-
return reference;
349-
});
350-
351-
symbolReferences.AddRange(symbolReferencesinFile);
352-
}
360+
reference.SourceLine = file.GetLine(reference.ScriptRegion.StartLineNumber);
361+
}
362+
catch (ArgumentOutOfRangeException e)
363+
{
364+
reference.SourceLine = string.Empty;
365+
this.logger.WriteException("Found reference is out of range in script file", e);
366+
}
353367

354-
return
355-
new FindReferencesResult
356-
{
357-
SymbolFileOffset = symbolOffset,
358-
SymbolName = foundSymbol.SymbolName,
359-
FoundReferences = symbolReferences
360-
};
368+
reference.FilePath = file.FilePath;
369+
return reference;
370+
});
371+
372+
symbolReferences.AddRange(symbolReferencesinFile);
361373
}
362-
else { return null; }
374+
375+
return new FindReferencesResult
376+
{
377+
SymbolFileOffset = symbolOffset,
378+
SymbolName = foundSymbol.SymbolName,
379+
FoundReferences = symbolReferences
380+
};
363381
}
364382

365383
/// <summary>

0 commit comments

Comments
 (0)