diff --git a/src/lsp.hh b/src/lsp.hh index b92578b8..a818dff9 100644 --- a/src/lsp.hh +++ b/src/lsp.hh @@ -261,6 +261,6 @@ struct ShowMessageParam { // 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 }; + enum class LanguageId { Unknown = -1, C = 0, Cpp = 1, ObjC = 2, ObjCpp = 3, CUDA = 4 }; } // namespace ccls diff --git a/src/project.cc b/src/project.cc index 10359515..4a9daf34 100644 --- a/src/project.cc +++ b/src/project.cc @@ -59,7 +59,9 @@ std::pair lookupExtension(std::string_view filename) { I == types::TY_ObjCXXHeader; bool objc = types::isObjC(I); LanguageId ret; - if (types::isCXX(I)) + if (I == types::TY_CUDA) + ret = LanguageId::CUDA; + else if (types::isCXX(I)) ret = objc ? LanguageId::ObjCpp : LanguageId::Cpp; else if (objc) ret = LanguageId::ObjC; @@ -123,6 +125,8 @@ struct ProjectProcessor { ok |= lang == LanguageId::ObjC; else if (A.consume_front("%objective-cpp ")) ok |= lang == LanguageId::ObjCpp; + else if (A.consume_front("%cu ")) + ok |= lang == LanguageId::CUDA; else break; } @@ -326,6 +330,13 @@ int ComputeGuessScore(std::string_view a, std::string_view b) { } // namespace +template +auto as_integer(Enumeration const value) + -> typename std::underlying_type::type +{ + return static_cast::type>(value); +} + void Project::LoadDirectory(const std::string &root, Project::Folder &folder) { SmallString<256> CDBDir, Path, StdinPath; std::string err_msg; @@ -412,11 +423,45 @@ void Project::LoadDirectory(const std::string &root, Project::Folder &folder) { DoPathMapping(entry.filename); std::vector args = std::move(Cmd.CommandLine); - entry.args.reserve(args.size()); - for (std::string &arg : args) { - DoPathMapping(arg); - if (!proc.ExcludesArg(arg)) - entry.args.push_back(Intern(arg)); + + auto [lang, header] = lookupExtension(entry.filename); + + // CMAKE splits nvcc compiles into 2 seperates commands, and has (mostly) non-clang arguments. Replace these with a simple call to clang with only "-I /path/header.h" arguments. + // .ccls will also need: + // clang + // %cu --cuda-gpu-arch=sm_70 --cuda-path=/usr/local/cuda-9.2/ + if(lang == LanguageId::CUDA) { + entry.args.push_back(Intern("/usr/bin/clang-7")); + entry.args.push_back(Intern("-c")); + entry.args.push_back(Intern(entry.filename)); + LOG_S(INFO) << entry.filename << ": (CUDA) clang-7 -c filename"; + bool take_next_arg = false; + for (std::string &arg : args) { + // take header includes (-I /path/to/header.h) + if(arg == "-I") { + entry.args.push_back(Intern(arg)); + take_next_arg = true; + } + else if (take_next_arg) { + // take actual header include location (/path/to/header.h) + entry.args.push_back(Intern(arg)); + take_next_arg = false; + } + else { + LOG_S(INFO) << entry.filename << ": (CUDA) Ignoring arg: " << arg; + } + } + } + else { + entry.args.reserve(args.size()); + for (std::string &arg : args) { + DoPathMapping(arg); + if (!proc.ExcludesArg(arg)) { + // LOG_S(INFO) << entry.filename << ": Accepted arg: " << arg << + // "\n"; + entry.args.push_back(Intern(arg)); + } + } } entry.compdb_size = entry.args.size();