private IEnumerable <IncludeDefinition> ProcessInclude(VirtualFile findResultIncludeFile, VirtualDirectory findResultIncludeBaseDirectory, List <CodeSpecificException> codeSpecificExceptions, IIncludeCacheTransaction cacheTransaction, CppCodeModel codeModel) { ParserResult parserResult = fileParser.Parse(findResultIncludeFile); if (!parserResult.Success) { codeSpecificExceptions.AddRange(parserResult.Exceptions); cacheTransaction.AddEntry(new IncludeCacheEntry(findResultIncludeFile.FullName, false, findResultIncludeFile.LastWriteTime, findResultIncludeBaseDirectory.FullName, Enumerable.Empty <string>(), Enumerable.Empty <string>(), new Dictionary <string, string>(), Enumerable.Empty <IConstant>())); return(Enumerable.Empty <IncludeDefinition>()); } foreach (IType type in parserResult.Types.Keys) { codeModel.AddType(type, findResultIncludeFile, findResultIncludeBaseDirectory); } codeModel.AddDefineStatements(parserResult.DefineStatements); codeModel.AddConstants(parserResult.Constants); codeSpecificExceptions.AddRange(parserResult.Exceptions); cacheTransaction.AddEntry(new IncludeCacheEntry(findResultIncludeFile.FullName, true, findResultIncludeFile.LastWriteTime, findResultIncludeBaseDirectory.FullName, parserResult.Types.Keys.Select(t => t.FullName), parserResult.Includes, parserResult.DefineStatements, parserResult.Constants)); return(parserResult.Includes.Select(i => new IncludeDefinition(i, findResultIncludeFile, findResultIncludeBaseDirectory))); }
public IEnumerable <CodeSpecificException> InitializeCodeModel(CppCodeModel codeModel, IncludeManagerParameter parameter) { HashSet <string> parsedIncludes = new HashSet <string>(parameter.KnownIncludes); List <CodeSpecificException> codeSpecificExceptions = new List <CodeSpecificException>(); VirtualFile cacheFile = fileSystem.GetFile(IncludeFilePath.CleanPath().ResolvePathName(environmentService.PathNames)); includeCache.LoadCache(cacheFile); UpdateCache(); codeModel.IncludeDirectories = parameter.IncludeDirectories; codeModel.RegisterIncludeTypeFinder(s => FindIncludeType(s, parameter.IncludeDirectories)); this.codeModel = codeModel; return(codeSpecificExceptions); void UpdateCache() { log.LogVerbose("Start updating the include cache."); Stopwatch loadWatch = new Stopwatch(); loadWatch.Start(); using (IIncludeCacheTransaction cacheTransaction = includeCache.StartTransaction()) { Stopwatch checkWatch = new Stopwatch(); checkWatch.Start(); foreach (IncludeCacheEntry staleEntry in FindStaleAndOutdatedEntries().ToArray()) { cacheTransaction.DeleteEntry(staleEntry); } checkWatch.Stop(); log.LogVerbose($"Checked files in {checkWatch.ElapsedMilliseconds} ms."); AddOrUpdate(parameter.IncludeDefinitions, cacheTransaction); } loadWatch.Stop(); log.LogVerbose($"Finished updating the include cache in {loadWatch.ElapsedMilliseconds} ms."); IEnumerable <IncludeCacheEntry> FindStaleAndOutdatedEntries() { return(includeCache.Entries.Where(e => !fileSystem.FileExists(e.File) || fileSystem.GetLastWriteTime(e.File) != e.LastWriteTime)); } void AddOrUpdate(IEnumerable <IncludeDefinition> includes, IIncludeCacheTransaction cacheTransaction) { Stack <IncludeDefinition> unvisited = new Stack <IncludeDefinition>(includes); while (unvisited.Any()) { IncludeDefinition include = unvisited.Pop(); if (TryFindInclude(include, out IncludeFindResult findResult)) { IEnumerable <IncludeDefinition> childDefinitions; if (findResult.IsInCache) { VirtualFile cacheSourceFile = fileSystem.GetFile(findResult.IncludeCacheEntry.File); VirtualDirectory cacheBaseDirectory = fileSystem.GetDirectory(findResult.IncludeCacheEntry.BaseDirectory); parsedIncludes.Add(cacheSourceFile.GetRelativePath(cacheBaseDirectory)); childDefinitions = findResult.IncludeCacheEntry.Includes .Select(i => new IncludeDefinition(i, cacheSourceFile, cacheBaseDirectory)); } else { parsedIncludes.Add(findResult.IncludeFile.GetRelativePath(findResult.IncludeBaseDirectory)); childDefinitions = ProcessInclude(findResult.IncludeFile, findResult.IncludeBaseDirectory); } foreach (IncludeDefinition childDefinition in childDefinitions) { unvisited.Push(childDefinition); } } } IEnumerable <IncludeDefinition> ProcessInclude(VirtualFile findResultIncludeFile, VirtualDirectory findResultIncludeBaseDirectory) { ParserResult parserResult = fileParser.Parse(findResultIncludeFile); if (!parserResult.Success) { codeSpecificExceptions.AddRange(parserResult.Exceptions); cacheTransaction.AddEntry(new IncludeCacheEntry(findResultIncludeFile.FullName, false, findResultIncludeFile.LastWriteTime, findResultIncludeBaseDirectory.FullName, Enumerable.Empty <string>(), Enumerable.Empty <string>())); return(Enumerable.Empty <IncludeDefinition>()); } foreach (IType type in parserResult.Types.Keys) { codeModel.AddType(type, findResultIncludeFile, findResultIncludeBaseDirectory); } codeSpecificExceptions.AddRange(parserResult.Exceptions); cacheTransaction.AddEntry(new IncludeCacheEntry(findResultIncludeFile.FullName, true, findResultIncludeFile.LastWriteTime, findResultIncludeBaseDirectory.FullName, parserResult.Types.Keys.Select(t => t.FullName), parserResult.Includes)); return(parserResult.Includes.Select( i => new IncludeDefinition( i, findResultIncludeFile, findResultIncludeBaseDirectory))); } bool TryFindInclude(IncludeDefinition current, out IncludeFindResult result) { if (current.Include.Trim().StartsWith("<", StringComparison.Ordinal)) { //system includes in form <algorithms> are ignored result = null; return(false); } //Try parse relative to source if (current.DefinitionSourceFile.Parent.TryGetFileFromPath(current.Include, out VirtualFile file)) { if (parsedIncludes.Contains(file.GetRelativePath(current.DefinitionSourceBaseDirectory))) { result = null; return(false); } result = includeCache.TryGetCacheEntry(file.FullName, out IncludeCacheEntry cacheEntry) ? new IncludeFindResult(cacheEntry) : new IncludeFindResult(file, current.DefinitionSourceBaseDirectory); return(true); } //Parse relative to include path foreach (VirtualDirectory includeDirectory in parameter.IncludeDirectories.Values.Where(v => v != null)) { if (includeDirectory.TryGetFileFromPath(current.Include, out file)) { if (parsedIncludes.Contains(file.GetRelativePath(includeDirectory))) { result = null; return(false); } result = includeCache.TryGetCacheEntry(file.FullName, out IncludeCacheEntry cacheEntry) ? new IncludeFindResult(cacheEntry) : new IncludeFindResult(file, includeDirectory); return(true); } } log.LogWarning($"Could not find include {current.Include}. Possible types from these files will not be parsed."); result = null; return(false); } } } }