diff --git a/CMakeLists.txt b/CMakeLists.txt index 29a3008f..7af3eb16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,7 +188,6 @@ target_sources(ccls PRIVATE src/include_complete.cc src/indexer.cc src/method.cc - src/language.cc src/log.cc src/lsp.cc src/match.cc diff --git a/src/indexer.h b/src/indexer.h index b70dbe43..c49f74e6 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -3,7 +3,6 @@ #pragma once -#include "language.h" #include "lsp.h" #include "lsp_diagnostic.h" #include "maybe.h" @@ -23,6 +22,7 @@ #include using Usr = uint64_t; +enum class LanguageId; struct SymbolIdx { Usr usr; diff --git a/src/language.cc b/src/language.cc deleted file mode 100644 index 561be92c..00000000 --- a/src/language.cc +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2017-2018 ccls Authors -// SPDX-License-Identifier: Apache-2.0 - -#include "language.h" - -#include "utils.h" - -LanguageId SourceFileLanguage(std::string_view path) { - if (EndsWith(path, ".c")) - return LanguageId::C; - else if (EndsWith(path, ".cpp") || EndsWith(path, ".cc")) - return LanguageId::Cpp; - else if (EndsWith(path, ".mm")) - return LanguageId::ObjCpp; - else if (EndsWith(path, ".m")) - return LanguageId::ObjC; - return LanguageId::Unknown; -} - -const char *LanguageIdentifier(LanguageId lang) { - switch (lang) { - case LanguageId::C: - return "c"; - case LanguageId::Cpp: - return "cpp"; - case LanguageId::ObjC: - return "objective-c"; - case LanguageId::ObjCpp: - return "objective-cpp"; - default: - return ""; - } -} diff --git a/src/language.h b/src/language.h deleted file mode 100644 index 94dc2697..00000000 --- a/src/language.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017-2018 ccls Authors -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include "serializer.h" - -#include - -// Used to identify the language at a file level. The ordering is important, as -// a file previously identified as `C`, will be changed to `Cpp` if it -// encounters a c++ declaration. -enum class LanguageId { Unknown = -1, C = 0, Cpp = 1, ObjC = 2, ObjCpp = 3 }; -MAKE_REFLECT_TYPE_PROXY(LanguageId); - -LanguageId SourceFileLanguage(std::string_view path); -const char *LanguageIdentifier(LanguageId lang); diff --git a/src/lsp.h b/src/lsp.h index 722f9cbe..be2d767a 100644 --- a/src/lsp.h +++ b/src/lsp.h @@ -334,3 +334,9 @@ struct Out_LocationList : public lsOutMessage { std::vector result; }; MAKE_REFLECT_STRUCT(Out_LocationList, jsonrpc, id, result); + +// Used to identify the language at a file level. The ordering is important, as +// a file previously identified as `C`, will be changed to `Cpp` if it +// encounters a c++ declaration. +enum class LanguageId { Unknown = -1, C = 0, Cpp = 1, ObjC = 2, ObjCpp = 3 }; +MAKE_REFLECT_TYPE_PROXY(LanguageId); diff --git a/src/main.cc b/src/main.cc index 66c818b7..4da4cb0f 100644 --- a/src/main.cc +++ b/src/main.cc @@ -30,17 +30,19 @@ using namespace llvm::cl; std::string g_init_options; namespace { -opt opt_help("h", desc("Alias for -help")); -opt opt_verbose("v", desc("verbosity"), init(0)); +OptionCategory C("ccls options"); + +opt opt_help("h", desc("Alias for -help"), cat(C)); +opt opt_verbose("v", desc("verbosity"), init(0), cat(C)); opt opt_test_index("test-index", ValueOptional, init("!"), - desc("run index tests")); + desc("run index tests"), cat(C)); -opt opt_init("init", desc("extra initialization options")); -opt opt_log_file("log-file", desc("log"), value_desc("filename")); +opt opt_init("init", desc("extra initialization options in JSON"), + cat(C)); +opt opt_log_file("log-file", desc("log"), value_desc("filename"), + cat(C)); opt opt_log_file_append("log-file-append", desc("log"), - value_desc("filename")); - -list opt_extra(Positional, ZeroOrMore, desc("extra")); + value_desc("filename"), cat(C)); void CloseLog() { fclose(ccls::log::file); } @@ -50,6 +52,10 @@ int main(int argc, char **argv) { TraceMe(); sys::PrintStackTraceOnErrorSignal(argv[0]); + for (auto &I : TopLevelSubCommand->OptionsMap) + if (I.second->Category != &C) + I.second->setHiddenFlag(ReallyHidden); + ParseCommandLineOptions(argc, argv, "C/C++/Objective-C language server\n\n" "See more on https://github.com/MaskRay/ccls/wiki"); diff --git a/src/messages/textDocument_did.cc b/src/messages/textDocument_did.cc index 67fc5539..a76f8889 100644 --- a/src/messages/textDocument_did.cc +++ b/src/messages/textDocument_did.cc @@ -115,7 +115,8 @@ struct Handler_TextDocumentDidOpen // Submit new index request if it is not a header file or there is no // pending index request. - if (SourceFileLanguage(path) != LanguageId::Unknown || + std::pair lang = lookupExtension(path); + if ((lang.first != LanguageId::Unknown && !lang.second) || !pipeline::pending_index_requests) pipeline::Index(path, args, IndexMode::Normal); diff --git a/src/messages/textDocument_hover.cc b/src/messages/textDocument_hover.cc index 920f6ff3..548eae8c 100644 --- a/src/messages/textDocument_hover.cc +++ b/src/messages/textDocument_hover.cc @@ -9,6 +9,18 @@ using namespace ccls; namespace { MethodType kMethodType = "textDocument/hover"; +const char *LanguageIdentifier(LanguageId lang) { + switch (lang) { + // clang-format off + case LanguageId::C: return "c"; + case LanguageId::Cpp: return "cpp"; + case LanguageId::ObjC: return "objective-c"; + case LanguageId::ObjCpp: return "objective-cpp"; + default: return ""; + // clang-format on + } +} + // Returns the hover or detailed name for `sym`, if any. std::pair, std::optional> GetHover(DB *db, LanguageId lang, SymbolRef sym, int file_id) { diff --git a/src/project.cc b/src/project.cc index 92a7ee61..c2b4390e 100644 --- a/src/project.cc +++ b/src/project.cc @@ -4,7 +4,6 @@ #include "project.h" #include "filesystem.hh" -#include "language.h" #include "log.hh" #include "match.h" #include "pipeline.hh" @@ -15,6 +14,7 @@ #include #include +#include #include #include #include @@ -35,6 +35,25 @@ using namespace ccls; using namespace clang; using namespace llvm; +std::pair lookupExtension(std::string_view filename) { + using namespace clang::driver; + auto I = types::lookupTypeForExtension( + sys::path::extension({filename.data(), filename.size()}).substr(1)); + bool header = I == types::TY_CHeader || I == types::TY_CXXHeader || + I == types::TY_ObjCXXHeader; + bool objc = types::isObjC(I); + LanguageId ret; + if (types::isCXX(I)) + ret = objc ? LanguageId::ObjCpp : LanguageId::Cpp; + else if (objc) + ret = LanguageId::ObjC; + else if (I == types::TY_C || I == types::TY_CHeader) + ret = LanguageId::C; + else + ret = LanguageId::Unknown; + return {ret, header}; +} + namespace { enum class ProjectMode { CompileCommandsJson, DotCcls, ExternalCommand }; @@ -64,7 +83,7 @@ struct ProjectProcessor { // Expand %c %cpp %clang std::vector args; args.reserve(entry.args.size() + g_config->clang.extraArgs.size() + 1); - const LanguageId lang = SourceFileLanguage(entry.filename); + const LanguageId lang = lookupExtension(entry.filename).first; for (const char *arg : entry.args) { if (strncmp(arg, "%c ", 3) == 0) { if (lang == LanguageId::C) @@ -86,7 +105,7 @@ struct ProjectProcessor { size_t hash = std::hash{}(entry.directory); for (auto &arg : args) { if (arg[0] != '-' && EndsWith(arg, base_name)) { - const LanguageId lang = SourceFileLanguage(arg); + LanguageId lang = lookupExtension(arg).first; if (lang != LanguageId::Unknown) { hash_combine(hash, size_t(lang)); continue; @@ -170,12 +189,6 @@ ReadCompilerArgumentsFromFile(const std::string &path) { std::vector LoadFromDirectoryListing(ProjectConfig *config) { std::vector result; config->mode = ProjectMode::DotCcls; - SmallString<256> Path; - sys::path::append(Path, config->root, ".ccls"); - LOG_IF_S(WARNING, !sys::fs::exists(Path) && g_config->clang.extraArgs.empty()) - << "ccls has no clang arguments. Use either " - "compile_commands.json or .ccls, See ccls README for " - "more information."; std::unordered_map> folder_args; std::vector files; @@ -184,7 +197,8 @@ std::vector LoadFromDirectoryListing(ProjectConfig *config) { GetFilesInFolder(root, true /*recursive*/, true /*add_folder_to_path*/, [&folder_args, &files](const std::string &path) { - if (SourceFileLanguage(path) != LanguageId::Unknown) { + std::pair lang = lookupExtension(path); + if (lang.first != LanguageId::Unknown && !lang.second) { files.push_back(path); } else if (sys::path::filename(path) == ".ccls") { std::vector args = ReadCompilerArgumentsFromFile(path); @@ -235,14 +249,13 @@ std::vector LoadEntriesFromDirectory(ProjectConfig *project, const std::string &opt_compdb_dir) { // If there is a .ccls file always load using directory listing. - SmallString<256> Path; - sys::path::append(Path, project->root, ".ccls"); - if (sys::fs::exists(Path)) + SmallString<256> Path, CclsPath; + sys::path::append(CclsPath, project->root, ".ccls"); + if (sys::fs::exists(CclsPath)) return LoadFromDirectoryListing(project); // If |compilationDatabaseCommand| is specified, execute it to get the compdb. std::string comp_db_dir; - Path.clear(); if (g_config->compilationDatabaseCommand.empty()) { project->mode = ProjectMode::CompileCommandsJson; // Try to load compile_commands.json, but fallback to a project listing. @@ -284,8 +297,8 @@ LoadEntriesFromDirectory(ProjectConfig *project, #endif } if (!CDB) { - LOG_S(WARNING) << "failed to load " << Path.c_str() << " " << err_msg; - return {}; + LOG_S(WARNING) << "no .ccls or compile_commands.json . Consider adding one"; + return LoadFromDirectoryListing(project); } LOG_S(INFO) << "loaded " << Path.c_str(); diff --git a/src/project.h b/src/project.h index de60ef69..c90032ce 100644 --- a/src/project.h +++ b/src/project.h @@ -4,6 +4,7 @@ #pragma once #include "config.h" +#include "lsp.h" #include "method.h" #include @@ -14,6 +15,8 @@ struct WorkingFiles; +std::pair lookupExtension(std::string_view filename); + struct Project { struct Entry { std::string root;