Misc changes to project

* Better LanguageId detection with clangDriver (e.g. .cu -> types::TY_CUDA)
* fallback when there is no .ccls or compile_commands.json

Also Hide clangTooling options from --help
This commit is contained in:
Fangrui Song 2018-10-13 23:22:29 -07:00
parent 40b47f9ca3
commit 4a1eea75db
10 changed files with 67 additions and 77 deletions

View File

@ -188,7 +188,6 @@ target_sources(ccls PRIVATE
src/include_complete.cc src/include_complete.cc
src/indexer.cc src/indexer.cc
src/method.cc src/method.cc
src/language.cc
src/log.cc src/log.cc
src/lsp.cc src/lsp.cc
src/match.cc src/match.cc

View File

@ -3,7 +3,6 @@
#pragma once #pragma once
#include "language.h"
#include "lsp.h" #include "lsp.h"
#include "lsp_diagnostic.h" #include "lsp_diagnostic.h"
#include "maybe.h" #include "maybe.h"
@ -23,6 +22,7 @@
#include <vector> #include <vector>
using Usr = uint64_t; using Usr = uint64_t;
enum class LanguageId;
struct SymbolIdx { struct SymbolIdx {
Usr usr; Usr usr;

View File

@ -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 "";
}
}

View File

@ -1,17 +0,0 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include "serializer.h"
#include <string_view>
// 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);

View File

@ -334,3 +334,9 @@ struct Out_LocationList : public lsOutMessage<Out_LocationList> {
std::vector<lsLocation> result; std::vector<lsLocation> result;
}; };
MAKE_REFLECT_STRUCT(Out_LocationList, jsonrpc, id, 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);

View File

@ -30,17 +30,19 @@ using namespace llvm::cl;
std::string g_init_options; std::string g_init_options;
namespace { namespace {
opt<bool> opt_help("h", desc("Alias for -help")); OptionCategory C("ccls options");
opt<int> opt_verbose("v", desc("verbosity"), init(0));
opt<bool> opt_help("h", desc("Alias for -help"), cat(C));
opt<int> opt_verbose("v", desc("verbosity"), init(0), cat(C));
opt<std::string> opt_test_index("test-index", ValueOptional, init("!"), opt<std::string> opt_test_index("test-index", ValueOptional, init("!"),
desc("run index tests")); desc("run index tests"), cat(C));
opt<std::string> opt_init("init", desc("extra initialization options")); opt<std::string> opt_init("init", desc("extra initialization options in JSON"),
opt<std::string> opt_log_file("log-file", desc("log"), value_desc("filename")); cat(C));
opt<std::string> opt_log_file("log-file", desc("log"), value_desc("filename"),
cat(C));
opt<std::string> opt_log_file_append("log-file-append", desc("log"), opt<std::string> opt_log_file_append("log-file-append", desc("log"),
value_desc("filename")); value_desc("filename"), cat(C));
list<std::string> opt_extra(Positional, ZeroOrMore, desc("extra"));
void CloseLog() { fclose(ccls::log::file); } void CloseLog() { fclose(ccls::log::file); }
@ -50,6 +52,10 @@ int main(int argc, char **argv) {
TraceMe(); TraceMe();
sys::PrintStackTraceOnErrorSignal(argv[0]); sys::PrintStackTraceOnErrorSignal(argv[0]);
for (auto &I : TopLevelSubCommand->OptionsMap)
if (I.second->Category != &C)
I.second->setHiddenFlag(ReallyHidden);
ParseCommandLineOptions(argc, argv, ParseCommandLineOptions(argc, argv,
"C/C++/Objective-C language server\n\n" "C/C++/Objective-C language server\n\n"
"See more on https://github.com/MaskRay/ccls/wiki"); "See more on https://github.com/MaskRay/ccls/wiki");

View File

@ -115,7 +115,8 @@ struct Handler_TextDocumentDidOpen
// Submit new index request if it is not a header file or there is no // Submit new index request if it is not a header file or there is no
// pending index request. // pending index request.
if (SourceFileLanguage(path) != LanguageId::Unknown || std::pair<LanguageId, bool> lang = lookupExtension(path);
if ((lang.first != LanguageId::Unknown && !lang.second) ||
!pipeline::pending_index_requests) !pipeline::pending_index_requests)
pipeline::Index(path, args, IndexMode::Normal); pipeline::Index(path, args, IndexMode::Normal);

View File

@ -9,6 +9,18 @@ using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/hover"; 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. // Returns the hover or detailed name for `sym`, if any.
std::pair<std::optional<lsMarkedString>, std::optional<lsMarkedString>> std::pair<std::optional<lsMarkedString>, std::optional<lsMarkedString>>
GetHover(DB *db, LanguageId lang, SymbolRef sym, int file_id) { GetHover(DB *db, LanguageId lang, SymbolRef sym, int file_id) {

View File

@ -4,7 +4,6 @@
#include "project.h" #include "project.h"
#include "filesystem.hh" #include "filesystem.hh"
#include "language.h"
#include "log.hh" #include "log.hh"
#include "match.h" #include "match.h"
#include "pipeline.hh" #include "pipeline.hh"
@ -15,6 +14,7 @@
#include <clang/Driver/Compilation.h> #include <clang/Driver/Compilation.h>
#include <clang/Driver/Driver.h> #include <clang/Driver/Driver.h>
#include <clang/Driver/Types.h>
#include <clang/Frontend/CompilerInstance.h> #include <clang/Frontend/CompilerInstance.h>
#include <clang/Tooling/CompilationDatabase.h> #include <clang/Tooling/CompilationDatabase.h>
#include <llvm/ADT/STLExtras.h> #include <llvm/ADT/STLExtras.h>
@ -35,6 +35,25 @@ using namespace ccls;
using namespace clang; using namespace clang;
using namespace llvm; using namespace llvm;
std::pair<LanguageId, bool> 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 { namespace {
enum class ProjectMode { CompileCommandsJson, DotCcls, ExternalCommand }; enum class ProjectMode { CompileCommandsJson, DotCcls, ExternalCommand };
@ -64,7 +83,7 @@ struct ProjectProcessor {
// Expand %c %cpp %clang // Expand %c %cpp %clang
std::vector<const char *> args; std::vector<const char *> args;
args.reserve(entry.args.size() + g_config->clang.extraArgs.size() + 1); 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) { for (const char *arg : entry.args) {
if (strncmp(arg, "%c ", 3) == 0) { if (strncmp(arg, "%c ", 3) == 0) {
if (lang == LanguageId::C) if (lang == LanguageId::C)
@ -86,7 +105,7 @@ struct ProjectProcessor {
size_t hash = std::hash<std::string>{}(entry.directory); size_t hash = std::hash<std::string>{}(entry.directory);
for (auto &arg : args) { for (auto &arg : args) {
if (arg[0] != '-' && EndsWith(arg, base_name)) { if (arg[0] != '-' && EndsWith(arg, base_name)) {
const LanguageId lang = SourceFileLanguage(arg); LanguageId lang = lookupExtension(arg).first;
if (lang != LanguageId::Unknown) { if (lang != LanguageId::Unknown) {
hash_combine(hash, size_t(lang)); hash_combine(hash, size_t(lang));
continue; continue;
@ -170,12 +189,6 @@ ReadCompilerArgumentsFromFile(const std::string &path) {
std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig *config) { std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig *config) {
std::vector<Project::Entry> result; std::vector<Project::Entry> result;
config->mode = ProjectMode::DotCcls; 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<std::string, std::vector<const char *>> folder_args; std::unordered_map<std::string, std::vector<const char *>> folder_args;
std::vector<std::string> files; std::vector<std::string> files;
@ -184,7 +197,8 @@ std::vector<Project::Entry> LoadFromDirectoryListing(ProjectConfig *config) {
GetFilesInFolder(root, true /*recursive*/, GetFilesInFolder(root, true /*recursive*/,
true /*add_folder_to_path*/, true /*add_folder_to_path*/,
[&folder_args, &files](const std::string &path) { [&folder_args, &files](const std::string &path) {
if (SourceFileLanguage(path) != LanguageId::Unknown) { std::pair<LanguageId, bool> lang = lookupExtension(path);
if (lang.first != LanguageId::Unknown && !lang.second) {
files.push_back(path); files.push_back(path);
} else if (sys::path::filename(path) == ".ccls") { } else if (sys::path::filename(path) == ".ccls") {
std::vector<const char *> args = ReadCompilerArgumentsFromFile(path); std::vector<const char *> args = ReadCompilerArgumentsFromFile(path);
@ -235,14 +249,13 @@ std::vector<Project::Entry>
LoadEntriesFromDirectory(ProjectConfig *project, LoadEntriesFromDirectory(ProjectConfig *project,
const std::string &opt_compdb_dir) { const std::string &opt_compdb_dir) {
// If there is a .ccls file always load using directory listing. // If there is a .ccls file always load using directory listing.
SmallString<256> Path; SmallString<256> Path, CclsPath;
sys::path::append(Path, project->root, ".ccls"); sys::path::append(CclsPath, project->root, ".ccls");
if (sys::fs::exists(Path)) if (sys::fs::exists(CclsPath))
return LoadFromDirectoryListing(project); return LoadFromDirectoryListing(project);
// If |compilationDatabaseCommand| is specified, execute it to get the compdb. // If |compilationDatabaseCommand| is specified, execute it to get the compdb.
std::string comp_db_dir; std::string comp_db_dir;
Path.clear();
if (g_config->compilationDatabaseCommand.empty()) { if (g_config->compilationDatabaseCommand.empty()) {
project->mode = ProjectMode::CompileCommandsJson; project->mode = ProjectMode::CompileCommandsJson;
// Try to load compile_commands.json, but fallback to a project listing. // Try to load compile_commands.json, but fallback to a project listing.
@ -284,8 +297,8 @@ LoadEntriesFromDirectory(ProjectConfig *project,
#endif #endif
} }
if (!CDB) { if (!CDB) {
LOG_S(WARNING) << "failed to load " << Path.c_str() << " " << err_msg; LOG_S(WARNING) << "no .ccls or compile_commands.json . Consider adding one";
return {}; return LoadFromDirectoryListing(project);
} }
LOG_S(INFO) << "loaded " << Path.c_str(); LOG_S(INFO) << "loaded " << Path.c_str();

View File

@ -4,6 +4,7 @@
#pragma once #pragma once
#include "config.h" #include "config.h"
#include "lsp.h"
#include "method.h" #include "method.h"
#include <functional> #include <functional>
@ -14,6 +15,8 @@
struct WorkingFiles; struct WorkingFiles;
std::pair<LanguageId, bool> lookupExtension(std::string_view filename);
struct Project { struct Project {
struct Entry { struct Entry {
std::string root; std::string root;