Example #1
0
        private void UpdateCache(IncludeManagerParameter parameter, HashSet <string> parsedIncludes, CppCodeModel codeModel, List <CodeSpecificException> codeSpecificExceptions)
        {
            log.LogVerbose("Start updating the include cache.");
            Stopwatch loadWatch = new Stopwatch();

            loadWatch.Start();
            using (IIncludeCacheTransaction cacheTransaction = includeCache.StartTransaction())
            {
                Stopwatch checkWatch = new Stopwatch();
                checkWatch.Start();

                IncludeCacheEntry[] staleEntries = includeCache.Version < JsonIncludeCache.CurrentVersion
                                                       ? includeCache.Entries.ToArray()
                                                       : FindStaleAndOutdatedEntries().ToArray();
                foreach (IncludeCacheEntry staleEntry in staleEntries)
                {
                    cacheTransaction.DeleteEntry(staleEntry);
                }

                checkWatch.Stop();
                log.LogVerbose($"Checked files in {checkWatch.ElapsedMilliseconds} ms.");

                AddOrUpdate(parameter.IncludeDefinitions, cacheTransaction, parsedIncludes, codeModel, codeSpecificExceptions, parameter);
            }

            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));
            }
        }
        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);
                    }
                }
            }
        }