From 94bd6fc301c5515b08898783982493ffdc6b189a Mon Sep 17 00:00:00 2001 From: Jacob Dufault Date: Sun, 21 May 2017 00:37:53 -0700 Subject: [PATCH] Add #include auto-complete. --- README.md | 2 +- src/clang_args | 4 + src/command_line.cc | 269 ++++++++++++++++++++++++++++---------- src/language_server_api.h | 34 ++--- src/project.cc | 103 ++++++++++++--- src/project.h | 5 + src/standard_includes.cc | 182 ++++++++++++++++++++++++++ src/standard_includes.h | 4 + 8 files changed, 501 insertions(+), 102 deletions(-) create mode 100644 src/standard_includes.cc create mode 100644 src/standard_includes.h diff --git a/README.md b/README.md index d4f2b5e2..48162660 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ be productive with cquery. Here's a list of implemented features: * diagnostics * code actions (clang FixIts) * darken/fade code disabled by preprocessor - * goto definition, document links on include to jump to file + * #include auto-complete and quick-jump (goto definition, document links) # Setup - build cquery, install extension, setup project diff --git a/src/clang_args b/src/clang_args index 96a7d180..2ecafe7c 100644 --- a/src/clang_args +++ b/src/clang_args @@ -10,6 +10,10 @@ -IC:/Users/jacob/Desktop/superindex/indexer/third_party/sparsehash/src -IC:/Users/jacob/Desktop/superindex/indexer/third_party/sparsepp -IC:/Program Files/LLVM/include +-IC:/Program Files (x86)/Windows Kits/10/Include/10.0.14393.0 +-IC:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include + + # OSX #-I/Users/jdufault/Personal/super-clang-index/third_party #-I/Users/jdufault/Personal/super-clang-index/third_party/doctest diff --git a/src/command_line.cc b/src/command_line.cc index 7c5677ac..24b07f06 100644 --- a/src/command_line.cc +++ b/src/command_line.cc @@ -9,6 +9,7 @@ #include "options.h" #include "project.h" #include "platform.h" +#include "standard_includes.h" #include "test.h" #include "timer.h" #include "threaded_queue.h" @@ -21,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -55,14 +57,14 @@ const int kExpectedClientVersion = 1; std::string FormatMicroseconds(long long microseconds) { - long long milliseconds = microseconds / 1000; - long long remaining = microseconds - milliseconds; +long long milliseconds = microseconds / 1000; +long long remaining = microseconds - milliseconds; - // Only show two digits after the dot. - while (remaining >= 100) - remaining /= 10; +// Only show two digits after the dot. +while (remaining >= 100) + remaining /= 10; - return std::to_string(milliseconds) + "." + std::to_string(remaining) + "ms"; +return std::to_string(milliseconds) + "." + std::to_string(remaining) + "ms"; } @@ -83,15 +85,15 @@ std::string FormatMicroseconds(long long microseconds) { // the user erases a character. vscode will resend the completion request if // that happens. struct CodeCompleteCache { - optional cached_path; - optional cached_completion_position; - NonElidedVector cached_results; - NonElidedVector cached_diagnostics; +optional cached_path; +optional cached_completion_position; +NonElidedVector cached_results; +NonElidedVector cached_diagnostics; - bool IsCacheValid(lsTextDocumentPositionParams position) const { - return cached_path == position.textDocument.uri.GetPath() && - cached_completion_position == position.position; - } +bool IsCacheValid(lsTextDocumentPositionParams position) const { + return cached_path == position.textDocument.uri.GetPath() && + cached_completion_position == position.position; +} }; @@ -103,27 +105,27 @@ struct CodeCompleteCache { struct IpcManager { - static IpcManager* instance_; - static IpcManager* instance() { - return instance_; - } - static void CreateInstance(MultiQueueWaiter* waiter) { - instance_ = new IpcManager(waiter); - } +static IpcManager* instance_; +static IpcManager* instance() { + return instance_; +} +static void CreateInstance(MultiQueueWaiter* waiter) { + instance_ = new IpcManager(waiter); +} - std::unique_ptr>> threaded_queue_for_client_; - std::unique_ptr>> threaded_queue_for_server_; +std::unique_ptr>> threaded_queue_for_client_; +std::unique_ptr>> threaded_queue_for_server_; - enum class Destination { - Client, Server - }; +enum class Destination { + Client, Server +}; - ThreadedQueue>* GetThreadedQueue(Destination destination) { - return destination == Destination::Client ? threaded_queue_for_client_.get() : threaded_queue_for_server_.get(); - } +ThreadedQueue>* GetThreadedQueue(Destination destination) { + return destination == Destination::Client ? threaded_queue_for_client_.get() : threaded_queue_for_server_.get(); +} - void SendOutMessageToClient(IpcId id, lsBaseOutMessage& response) { - std::ostringstream sstream; +void SendOutMessageToClient(IpcId id, lsBaseOutMessage& response) { + std::ostringstream sstream; response.Write(sstream); auto out = MakeUnique(); @@ -177,11 +179,70 @@ bool ShouldDisplayIpcTiming(IpcId id) { +std::string BaseName(const std::string& path) { + int i = path.size() - 1; + while (i > 0) { + char c = path[i - 1]; + if (c == '/' || c == '\\') + break; + --i; + } + return path.substr(i); +} + +int TrimCommonPathPrefix(const std::string& result, const std::string& trimmer) { + size_t i = 0; + while (i < result.size() && i < trimmer.size()) { + char a = result[i]; + char b = trimmer[i]; +#if defined(_WIN32) + a = tolower(a); + b = tolower(b); +#endif + if (a != b) + break; + ++i; + } + + if (i == trimmer.size()) + return i; + return 0; +} +// Returns true iff angle brackets should be used. +bool TrimPath(Project* project, const std::string& project_root, std::string& insert_path) { + int start = 0; + bool angle = false; + int len = TrimCommonPathPrefix(insert_path, project_root); + if (len > start) + start = len; + for (auto& include_dir : project->quote_include_directories) { + len = TrimCommonPathPrefix(insert_path, include_dir); + if (len > start) + start = len; + } + for (auto& include_dir : project->angle_include_directories) { + len = TrimCommonPathPrefix(insert_path, include_dir); + if (len > start) { + start = len; + angle = true; + } + } + + insert_path = insert_path.substr(start); + return angle; +} + +bool ShouldRunIncludeCompletion(const std::string& line) { + size_t start = 0; + while (start < line.size() && isspace(line[start])) + ++start; + return start < line.size() && line[start] == '#'; +} @@ -1477,6 +1538,11 @@ bool QueryDbMainLoop( config->cacheDirectory += '/'; MakeDirectoryRecursive(config->cacheDirectory); + // Set project root. + config->projectRoot = NormalizePath(request->params.rootUri->GetPath()); + if (config->projectRoot.empty() || config->projectRoot[config->projectRoot.size() - 1] != '/') + config->projectRoot += '/'; + // Start indexer threads. int indexer_count = std::max(std::thread::hardware_concurrency(), 2) - 1; if (config->indexerCount > 0) @@ -1520,7 +1586,7 @@ bool QueryDbMainLoop( response.result.capabilities.completionProvider->resolveProvider = false; // vscode doesn't support trigger character sequences, so we use ':' for '::' and '>' for '->'. // See https://github.com/Microsoft/language-server-protocol/issues/138. - response.result.capabilities.completionProvider->triggerCharacters = { ".", ":", ">" }; + response.result.capabilities.completionProvider->triggerCharacters = { ".", ":", ">", "#" }; response.result.capabilities.signatureHelpProvider = lsSignatureHelpOptions(); // NOTE: If updating signature help tokens make sure to also update @@ -1772,47 +1838,120 @@ bool QueryDbMainLoop( lsTextDocumentPositionParams& params = msg->params; WorkingFile* file = working_files->GetFileByFilename(params.textDocument.uri.GetPath()); - if (file) - params.position = file->FindStableCompletionSource(params.position); - CompletionManager::OnComplete callback = std::bind([working_files, code_complete_cache](BaseIpcMessage* message, NonElidedVector results, NonElidedVector diagnostics) { - auto msg = static_cast(message); - auto ipc = IpcManager::instance(); + // TODO: We should scan include directories to add any missing paths + std::string buffer_line = file->all_buffer_lines[params.position.line]; + + if (ShouldRunIncludeCompletion(buffer_line)) { Out_TextDocumentComplete complete_response; complete_response.id = msg->id; complete_response.result.isIncomplete = false; - complete_response.result.items = results; - // Emit completion results. + for (const char* stl_header : kStandardLibraryIncludes) { + lsCompletionItem item; + item.label = "#include <" + std::string(stl_header) + ">"; + item.insertTextFormat = lsInsertTextFormat::PlainText; + item.kind = lsCompletionItemKind::Module; + + // Replace the entire existing content. + item.textEdit = lsTextEdit(); + item.textEdit->range.start.line = params.position.line; + item.textEdit->range.start.character = 0; + item.textEdit->range.end.line = params.position.line; + item.textEdit->range.end.character = buffer_line.size(); + item.textEdit->newText = item.label; + + complete_response.result.items.push_back(item); + } + + for (optional& file : db->files) { + if (!file) + continue; + + // TODO: codify list of file extensions somewhere + if (EndsWith(file->def.path, ".c") || + EndsWith(file->def.path, ".cc") || + EndsWith(file->def.path, ".cpp")) + continue; + + lsCompletionItem item; + + // Standard library headers are handled differently. + std::string base_name = BaseName(file->def.path); + if (std::find(std::begin(kStandardLibraryIncludes), std::end(kStandardLibraryIncludes), base_name) != std::end(kStandardLibraryIncludes)) + continue; + + // Trim the path so it is relative to an include directory. + std::string insert_path = file->def.path; + std::string start_quote = "\""; + std::string end_quote = "\""; + if (TrimPath(project, config->projectRoot, insert_path)) { + start_quote = "<"; + end_quote = ">"; + } + + item.label = "#include " + start_quote + insert_path + end_quote; + item.insertTextFormat = lsInsertTextFormat::PlainText; + item.kind = lsCompletionItemKind::File; + + // Replace the entire existing content. + item.textEdit = lsTextEdit(); + item.textEdit->range.start.line = params.position.line; + item.textEdit->range.start.character = 0; + item.textEdit->range.end.line = params.position.line; + item.textEdit->range.end.character = buffer_line.size(); + item.textEdit->newText = item.label; + + complete_response.result.items.push_back(item); + } + + complete_response.Write(std::cerr); ipc->SendOutMessageToClient(IpcId::TextDocumentCompletion, complete_response); - - // Emit diagnostics. - Out_TextDocumentPublishDiagnostics diagnostic_response; - diagnostic_response.params.uri = msg->params.textDocument.uri; - diagnostic_response.params.diagnostics = diagnostics; - ipc->SendOutMessageToClient(IpcId::TextDocumentPublishDiagnostics, diagnostic_response); - - // Cache diagnostics so we can show fixits. - WorkingFile* working_file = working_files->GetFileByFilename(msg->params.textDocument.uri.GetPath()); - if (working_file) - working_file->diagnostics = diagnostics; - - // Cache completion results so if the user types backspace we can respond faster. - code_complete_cache->cached_path = msg->params.textDocument.uri.GetPath(); - code_complete_cache->cached_completion_position = msg->params.position; - code_complete_cache->cached_results = results; - code_complete_cache->cached_diagnostics = diagnostics; - - delete message; - }, message.release(), std::placeholders::_1, std::placeholders::_2); - - if (code_complete_cache->IsCacheValid(params)) { - std::cerr << "[complete] Using cached completion results at " << params.position.ToString() << std::endl; - callback(code_complete_cache->cached_results, code_complete_cache->cached_diagnostics); } else { - completion_manager->CodeComplete(params, std::move(callback)); + if (file) + params.position = file->FindStableCompletionSource(params.position); + + CompletionManager::OnComplete callback = std::bind([working_files, code_complete_cache](BaseIpcMessage* message, NonElidedVector results, NonElidedVector diagnostics) { + auto msg = static_cast(message); + auto ipc = IpcManager::instance(); + + Out_TextDocumentComplete complete_response; + complete_response.id = msg->id; + complete_response.result.isIncomplete = false; + complete_response.result.items = results; + + // Emit completion results. + ipc->SendOutMessageToClient(IpcId::TextDocumentCompletion, complete_response); + + // Emit diagnostics. + Out_TextDocumentPublishDiagnostics diagnostic_response; + diagnostic_response.params.uri = msg->params.textDocument.uri; + diagnostic_response.params.diagnostics = diagnostics; + ipc->SendOutMessageToClient(IpcId::TextDocumentPublishDiagnostics, diagnostic_response); + + // Cache diagnostics so we can show fixits. + WorkingFile* working_file = working_files->GetFileByFilename(msg->params.textDocument.uri.GetPath()); + if (working_file) + working_file->diagnostics = diagnostics; + + // Cache completion results so if the user types backspace we can respond faster. + code_complete_cache->cached_path = msg->params.textDocument.uri.GetPath(); + code_complete_cache->cached_completion_position = msg->params.position; + code_complete_cache->cached_results = results; + code_complete_cache->cached_diagnostics = diagnostics; + + delete message; + }, message.release(), std::placeholders::_1, std::placeholders::_2); + + if (code_complete_cache->IsCacheValid(params)) { + std::cerr << "[complete] Using cached completion results at " << params.position.ToString() << std::endl; + callback(code_complete_cache->cached_results, code_complete_cache->cached_diagnostics); + } + else { + completion_manager->CodeComplete(params, std::move(callback)); + } } break; @@ -1957,7 +2096,6 @@ bool QueryDbMainLoop( for (const IndexInclude& include : file->def.includes) { if (include.line == target_line) { lsLocation result; - std::cerr << "!! resolved to " << include.resolved_path << std::endl; result.uri = lsDocumentUri::FromPath(include.resolved_path); response.result.push_back(result); break; @@ -2158,7 +2296,6 @@ bool QueryDbMainLoop( } } - response.Write(std::cerr); ipc->SendOutMessageToClient(IpcId::TextDocumentDocumentLink, response); break; } diff --git a/src/language_server_api.h b/src/language_server_api.h index 7f000b3b..3a3a7b40 100644 --- a/src/language_server_api.h +++ b/src/language_server_api.h @@ -56,6 +56,9 @@ void Reflect(Reader& visitor, lsRequestId& id); struct IndexerConfig { + // Root directory of the project. **Not serialized** + std::string projectRoot; + std::string cacheDirectory; NonElidedVector whitelist; NonElidedVector blacklist; @@ -397,6 +400,19 @@ struct lsTextDocumentPositionParams { }; MAKE_REFLECT_STRUCT(lsTextDocumentPositionParams, textDocument, position); +struct lsTextEdit { + // The range of the text document to be manipulated. To insert + // text into a document create a range where start === end. + lsRange range; + + // The string to be inserted. For delete operations use an + // empty string. + std::string newText; + + bool operator==(const lsTextEdit& that); +}; +MAKE_REFLECT_STRUCT(lsTextEdit, range, newText); + // Defines whether the insert text in a completion item should be interpreted as // plain text or a snippet. enum class lsInsertTextFormat { @@ -479,7 +495,7 @@ struct lsCompletionItem { // // *Note:* The range of the edit must be a single line range and it must contain the position at which completion // has been requested. - // TextEdit textEdit; + optional textEdit; // An optional array of additional text edits that are applied when // selecting this completion. Edits must not overlap with the main edit @@ -502,7 +518,8 @@ MAKE_REFLECT_STRUCT(lsCompletionItem, documentation, sortText, insertText, - insertTextFormat); + insertTextFormat, + textEdit); struct lsTextDocumentItem { @@ -521,19 +538,6 @@ struct lsTextDocumentItem { }; MAKE_REFLECT_STRUCT(lsTextDocumentItem, uri, languageId, version, text); -struct lsTextEdit { - // The range of the text document to be manipulated. To insert - // text into a document create a range where start === end. - lsRange range; - - // The string to be inserted. For delete operations use an - // empty string. - std::string newText; - - bool operator==(const lsTextEdit& that); -}; -MAKE_REFLECT_STRUCT(lsTextEdit, range, newText); - struct lsTextDocumentEdit { // The text document to change. lsVersionedTextDocumentIdentifier textDocument; diff --git a/src/project.cc b/src/project.cc index 6df0d84a..75ca5827 100644 --- a/src/project.cc +++ b/src/project.cc @@ -82,17 +82,44 @@ static const char *kBlacklist[] = { // Arguments which are followed by a potentially relative path. We need to make // all relative paths absolute, otherwise libclang will not resolve them. const char* kPathArgs[] = { - "-isystem", "-I", "-iquote", + "-isystem", "--sysroot=" }; -Project::Entry GetCompilationEntryFromCompileCommandEntry(const std::vector& extra_flags, const CompileCommandsEntry& entry) { +const char* kQuoteIncludeArgs[] = { + "-iquote" +}; +const char* kAngleIncludeArgs[] = { + "-I", + "-isystem" +}; + +bool ShouldAddToQuoteIncludes(const std::string& arg) { + for (const char* flag_type : kQuoteIncludeArgs) { + if (arg == flag_type) + return true; + } + return false; +} +bool ShouldAddToAngleIncludes(const std::string& arg) { + for (const char* flag_type : kAngleIncludeArgs) { + if (StartsWith(arg, flag_type)) + return true; + } + return false; +} + +Project::Entry GetCompilationEntryFromCompileCommandEntry( + std::unordered_set& quote_includes, std::unordered_set& angle_includes, + const std::vector& extra_flags, const CompileCommandsEntry& entry) { Project::Entry result; result.filename = NormalizePath(entry.file); bool make_next_flag_absolute = false; + bool add_next_flag_quote = false; + bool add_next_flag_angle = false; result.args.reserve(entry.args.size() + extra_flags.size()); for (size_t i = 0; i < entry.args.size(); ++i) { @@ -116,26 +143,40 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(const std::vector 0 && arg[0] != '/') arg = NormalizePath(entry.directory + arg); make_next_flag_absolute = false; + + if (add_next_flag_quote) + quote_includes.insert(arg); + if (add_next_flag_angle) + angle_includes.insert(arg); + add_next_flag_quote = false; + add_next_flag_angle = false; } // Update arg if it is a path. for (const char* flag_type : kPathArgs) { if (arg == flag_type) { make_next_flag_absolute = true; + add_next_flag_quote = ShouldAddToQuoteIncludes(arg); + add_next_flag_angle = ShouldAddToAngleIncludes(arg); break; } if (StartsWith(arg, flag_type)) { std::string path = arg.substr(strlen(flag_type)); if (path.size() > 0 && path[0] != '/') { - path = NormalizePath(entry.directory + "/" + path); + if (!entry.directory.empty()) + path = entry.directory + "/" + path; + path = NormalizePath(path); + arg = flag_type + path; } + if (ShouldAddToQuoteIncludes(arg)) + quote_includes.insert(path); + if (ShouldAddToAngleIncludes(arg)) + angle_includes.insert(path); break; } } - if (make_next_flag_absolute) - continue; result.args.push_back(arg); } @@ -154,7 +195,9 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(const std::vector LoadFromCompileCommandsJson(const std::vector& extra_flags, const std::string& project_directory) { +std::vector LoadFromCompileCommandsJson( + std::unordered_set& quote_includes, std::unordered_set& angle_includes, + const std::vector& extra_flags, const std::string& project_directory) { // TODO: Fix this function, it may be way faster than libclang's implementation. optional compile_commands_content = ReadContent(project_directory + "/compile_commands.json"); @@ -175,12 +218,14 @@ std::vector LoadFromCompileCommandsJson(const std::vector LoadFromDirectoryListing(const std::vector& extra_flags, const std::string& project_directory) { +std::vector LoadFromDirectoryListing( + std::unordered_set& quote_includes, std::unordered_set& angle_includes, + const std::vector& extra_flags, const std::string& project_directory) { std::vector result; std::vector args; @@ -193,27 +238,25 @@ std::vector LoadFromDirectoryListing(const std::vector files = GetFilesInFolder(project_directory, true /*recursive*/, true /*add_folder_to_path*/); for (const std::string& file : files) { if (EndsWith(file, ".cc") || EndsWith(file, ".cpp") || EndsWith(file, ".c")) { - Project::Entry entry; - entry.filename = NormalizePath(file); - entry.args = args; - result.push_back(entry); + CompileCommandsEntry e; + e.file = NormalizePath(file); + e.args = args; + result.push_back(GetCompilationEntryFromCompileCommandEntry(quote_includes, angle_includes, extra_flags, e)); } } return result; } -std::vector LoadCompilationEntriesFromDirectory(const std::vector& extra_flags, const std::string& project_directory) { +std::vector LoadCompilationEntriesFromDirectory( + std::unordered_set& quote_includes, std::unordered_set& angle_includes, + const std::vector& extra_flags, const std::string& project_directory) { // TODO: Figure out if this function or the clang one is faster. //return LoadFromCompileCommandsJson(extra_flags, project_directory); @@ -222,7 +265,7 @@ std::vector LoadCompilationEntriesFromDirectory(const std::vecto CXCompilationDatabase cx_db = clang_CompilationDatabase_fromDirectory(project_directory.c_str(), &cx_db_load_error); if (cx_db_load_error == CXCompilationDatabase_CanNotLoadDatabase) { std::cerr << "Unable to load compile_commands.json located at \"" << project_directory << "\"; using directory listing instead." << std::endl; - return LoadFromDirectoryListing(extra_flags, project_directory); + return LoadFromDirectoryListing(quote_includes, angle_includes, extra_flags, project_directory); } CXCompileCommands cx_commands = clang_CompilationDatabase_getAllCompileCommands(cx_db); @@ -245,7 +288,7 @@ std::vector LoadCompilationEntriesFromDirectory(const std::vecto for (unsigned i = 0; i < num_args; ++i) entry.args.push_back(clang::ToString(clang_CompileCommand_getArg(cx_command, i))); - result.push_back(GetCompilationEntryFromCompileCommandEntry(extra_flags, entry)); + result.push_back(GetCompilationEntryFromCompileCommandEntry(quote_includes, angle_includes, extra_flags, entry)); } clang_CompileCommands_dispose(cx_commands); @@ -278,10 +321,30 @@ int ComputeGuessScore(const std::string& a, const std::string& b) { return score; } +void EnsureEndsInSlash(std::string& path) { + if (path.empty() || path[path.size() - 1] != '/') + path += '/'; +} + } // namespace void Project::Load(const std::vector& extra_flags, const std::string& directory) { - entries = LoadCompilationEntriesFromDirectory(extra_flags, directory); + std::unordered_set unique_quote_includes; + std::unordered_set unique_angle_includes; + + entries = LoadCompilationEntriesFromDirectory(unique_quote_includes, unique_angle_includes, extra_flags, directory); + + quote_include_directories.assign(unique_quote_includes.begin(), unique_quote_includes.end()); + angle_include_directories.assign(unique_angle_includes.begin(), unique_angle_includes.end()); + + for (std::string& path : quote_include_directories) { + EnsureEndsInSlash(path); + std::cerr << "quote_include_dir: " << path << std::endl; + } + for (std::string& path : angle_include_directories) { + EnsureEndsInSlash(path); + std::cerr << "angle_include_dir: " << path << std::endl; + } absolute_path_to_entry_index_.resize(entries.size()); for (int i = 0; i < entries.size(); ++i) diff --git a/src/project.h b/src/project.h index ef3861f7..4a9306b4 100644 --- a/src/project.h +++ b/src/project.h @@ -21,6 +21,11 @@ struct Project { bool is_inferred = false; }; + // Include directories for "" headers + std::vector quote_include_directories; + // Include directories for <> headers + std::vector angle_include_directories; + std::vector entries; spp::sparse_hash_map absolute_path_to_entry_index_; diff --git a/src/standard_includes.cc b/src/standard_includes.cc new file mode 100644 index 00000000..cda94b42 --- /dev/null +++ b/src/standard_includes.cc @@ -0,0 +1,182 @@ +#include "standard_includes.h" + +// See http://stackoverflow.com/a/2029106. +const char* kStandardLibraryIncludes[177] = { + "aio.h", + "algorithm", + "any", + "arpa/inet.h", + "array", + "assert.h", + "atomic", + "bitset", + "cassert", + "ccomplex", + "cctype", + "cerrno", + "cfenv", + "cfloat", + "chrono", + "cinttypes", + "ciso646", + "climits", + "clocale", + "cmath", + "codecvt", + "complex", + "complex.h", + "condition_variable", + "cpio.h", + "csetjmp", + "csignal", + "cstdalign", + "cstdarg", + "cstdbool", + "cstddef", + "cstdint", + "cstdio", + "cstdlib", + "cstring", + "ctgmath", + "ctime", + "ctype.h", + "cuchar", + "curses.h", + "cwchar", + "cwctype", + "deque", + "dirent.h", + "dlfcn.h", + "errno.h", + "exception", + "execution", + "fcntl.h", + "fenv.h", + "filesystem", + "float.h", + "fmtmsg.h", + "fnmatch.h", + "forward_list", + "fstream", + "ftw.h", + "functional", + "future", + "glob.h", + "grp.h", + "iconv.h", + "initializer_list", + "inttypes.h", + "iomanip", + "ios", + "iosfwd", + "iostream", + "iso646.h", + "istream", + "iterator", + "langinfo.h", + "libgen.h", + "limits", + "limits.h", + "list", + "locale", + "locale.h", + "map", + "math.h", + "memory", + "memory_resource", + "monetary.h", + "mqueue.h", + "mutex", + "ndbm.h", + "net/if.h", + "netdb.h", + "netinet/in.h", + "netinet/tcp.h", + "new", + "nl_types.h", + "numeric", + "optional", + "ostream", + "poll.h", + "pthread.h", + "pwd.h", + "queue", + "random", + "ratio", + "regex", + "regex.h", + "sched.h", + "scoped_allocator", + "search.h", + "semaphore.h", + "set", + "setjmp.h", + "shared_mutex", + "signal.h", + "spawn.h", + "sstream", + "stack", + "stdalign.h", + "stdarg.h", + "stdatomic.h", + "stdbool.h", + "stddef.h", + "stdexcept", + "stdint.h", + "stdio.h", + "stdlib.h", + "stdnoreturn.h", + "streambuf", + "string", + "string.h", + "string_view", + "strings.h", + "stropts.h", + "strstream", + "sys/ipc.h", + "sys/mman.h", + "sys/msg.h", + "sys/resource.h", + "sys/select.h", + "sys/sem.h", + "sys/shm.h", + "sys/socket.h", + "sys/stat.h", + "sys/statvfs.h", + "sys/time.h", + "sys/times.h", + "sys/types.h", + "sys/uio.h", + "sys/un.h", + "sys/utsname.h", + "sys/wait.h", + "syslog.h", + "system_error", + "tar.h", + "term.h", + "termios.h", + "tgmath.h", + "thread", + "threads.h", + "time.h", + "trace.h", + "tuple", + "type_traits", + "typeindex", + "typeinfo", + "uchar.h", + "ulimit.h", + "uncntrl.h", + "unistd.h", + "unordered_map", + "unordered_set", + "utility", + "utime.h", + "utmpx.h", + "valarray", + "variant", + "vector", + "wchar.h", + "wctype.h", + "wordexp.h", +}; \ No newline at end of file diff --git a/src/standard_includes.h b/src/standard_includes.h new file mode 100644 index 00000000..6c50227d --- /dev/null +++ b/src/standard_includes.h @@ -0,0 +1,4 @@ +#pragma once + +// A set of standard libary header names, ie, "vector". +extern const char* kStandardLibraryIncludes[177]; \ No newline at end of file