Goto definition for includes

This commit is contained in:
Jacob Dufault 2017-05-20 20:46:15 -07:00
parent c03f99ce1f
commit 41e1dff4c9
17 changed files with 471 additions and 16 deletions

View File

@ -28,6 +28,7 @@ be productive with cquery. Here's a list of implemented features:
* diagnostics * diagnostics
* code actions (clang FixIts) * code actions (clang FixIts)
* darken/fade code disabled by preprocessor * darken/fade code disabled by preprocessor
* goto definition on include to jump to file
# Setup - build cquery, install extension, setup project # Setup - build cquery, install extension, setup project

View File

@ -1,6 +1,7 @@
#include "clang_utils.h" #include "clang_utils.h"
#include "libclangmm/Utility.h" #include "libclangmm/Utility.h"
#include "platform.h"
namespace { namespace {
@ -79,3 +80,9 @@ optional<lsDiagnostic> BuildDiagnostic(CXDiagnostic diagnostic) {
return ls_diagnostic; return ls_diagnostic;
} }
std::string FileName(CXFile file) {
CXString cx_name = clang_getFileName(file);
std::string name = clang::ToString(cx_name);
return NormalizePath(name);
}

View File

@ -9,4 +9,7 @@
using namespace std::experimental; using namespace std::experimental;
optional<lsDiagnostic> BuildDiagnostic(CXDiagnostic diagnostic); optional<lsDiagnostic> BuildDiagnostic(CXDiagnostic diagnostic);
// Returns the absolute path to |file|.
std::string FileName(CXFile file);

View File

@ -1948,6 +1948,19 @@ bool QueryDbMainLoop(
break; break;
} }
// No symbols - check for includes.
if (response.result.empty()) {
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;
}
}
}
ipc->SendOutMessageToClient(IpcId::TextDocumentDefinition, response); ipc->SendOutMessageToClient(IpcId::TextDocumentDefinition, response);
break; break;
} }

View File

@ -1,19 +1,10 @@
#include "file_consumer.h" #include "file_consumer.h"
#include "clang_utils.h"
#include "indexer.h" #include "indexer.h"
#include "platform.h" #include "platform.h"
#include "utils.h" #include "utils.h"
namespace {
std::string FileName(CXFile file) {
CXString cx_name = clang_getFileName(file);
std::string name = clang::ToString(cx_name);
return NormalizePath(name);
}
} // namespace
bool operator==(const CXFileUniqueID& a, const CXFileUniqueID& b) { bool operator==(const CXFileUniqueID& a, const CXFileUniqueID& b) {
return a.data[0] == b.data[0] && a.data[1] == b.data[1] && a.data[2] == b.data[2]; return a.data[0] == b.data[0] && a.data[1] == b.data[1] && a.data[2] == b.data[2];
} }

View File

@ -328,8 +328,24 @@ CXIdxClientFile enteredMainFile(CXClientData client_data,
CXIdxClientFile ppIncludedFile(CXClientData client_data, CXIdxClientFile ppIncludedFile(CXClientData client_data,
const CXIdxIncludedFileInfo* file) { const CXIdxIncludedFileInfo* file) {
// Clang include logic is broken. This function is never IndexParam* param = static_cast<IndexParam*>(client_data);
// called and clang_findIncludesInFile doesn't work.
// file->hashLoc only has the position of the hash. We don't have the full
// range for the include.
CXSourceLocation hash_loc = clang_indexLoc_getCXSourceLocation(file->hashLoc);
CXFile cx_file;
unsigned int line;
clang_getSpellingLocation(hash_loc, &cx_file, &line, nullptr, nullptr);
IndexFile* db = ConsumeFile(param, cx_file);
if (!db)
return nullptr;
IndexInclude include;
include.line = line;
include.resolved_path = FileName(file->file);
db->includes.push_back(include);
return nullptr; return nullptr;
} }

View File

@ -494,6 +494,15 @@ struct IdCache {
IdCache(const std::string& primary_file); IdCache(const std::string& primary_file);
}; };
struct IndexInclude {
// Line that has the include directive. We don't have complete range
// information - a line is good enough for clicking.
int line = 0;
// Absolute path to the index.
std::string resolved_path;
};
MAKE_REFLECT_STRUCT(IndexInclude, line, resolved_path);
struct IndexFile { struct IndexFile {
IdCache id_cache; IdCache id_cache;
@ -516,6 +525,7 @@ struct IndexFile {
// Source ranges that were not processed. // Source ranges that were not processed.
std::vector<Range> skipped_by_preprocessor; std::vector<Range> skipped_by_preprocessor;
std::vector<IndexInclude> includes;
std::vector<std::string> dependencies; std::vector<std::string> dependencies;
std::vector<IndexType> types; std::vector<IndexType> types;
std::vector<IndexFunc> funcs; std::vector<IndexFunc> funcs;

View File

@ -164,6 +164,7 @@ void CompareGroups(
QueryFile::Def BuildFileDef(const IdMap& id_map, const IndexFile& indexed) { QueryFile::Def BuildFileDef(const IdMap& id_map, const IndexFile& indexed) {
QueryFile::Def def; QueryFile::Def def;
def.path = indexed.path; def.path = indexed.path;
def.includes = indexed.includes;
auto add_outline = [&def, &id_map](SymbolIdx idx, Range range) { auto add_outline = [&def, &id_map](SymbolIdx idx, Range range) {
def.outline.push_back(SymbolRef(idx, id_map.ToQuery(range))); def.outline.push_back(SymbolRef(idx, id_map.ToQuery(range)));

View File

@ -161,6 +161,8 @@ void Reflect(TVisitor& visitor, MergeableUpdate<TId, TValue>& value) {
struct QueryFile { struct QueryFile {
struct Def { struct Def {
std::string path; std::string path;
// Includes in the file.
std::vector<IndexInclude> includes;
// Outline of the file (ie, for code lens). // Outline of the file (ie, for code lens).
std::vector<SymbolRef> outline; std::vector<SymbolRef> outline;
// Every symbol found in the file (ie, for goto definition) // Every symbol found in the file (ie, for goto definition)

View File

@ -199,6 +199,7 @@ void Reflect(TVisitor& visitor, IndexFile& value) {
REFLECT_MEMBER(import_file); REFLECT_MEMBER(import_file);
REFLECT_MEMBER(args); REFLECT_MEMBER(args);
} }
REFLECT_MEMBER(includes);
REFLECT_MEMBER(dependencies); REFLECT_MEMBER(dependencies);
REFLECT_MEMBER(skipped_by_preprocessor); REFLECT_MEMBER(skipped_by_preprocessor);
REFLECT_MEMBER(types); REFLECT_MEMBER(types);

View File

@ -50,6 +50,10 @@ OUTPUT: funky_enum.h
} }
OUTPUT: funky_enum.cc OUTPUT: funky_enum.cc
{ {
"includes": [{
"line": 2,
"resolved_path": "C:/Users/jacob/Desktop/superindex/indexer/tests/multi_file/funky_enum.h"
}],
"dependencies": ["C:/Users/jacob/Desktop/superindex/indexer/tests/multi_file/funky_enum.h"], "dependencies": ["C:/Users/jacob/Desktop/superindex/indexer/tests/multi_file/funky_enum.h"],
"types": [{ "types": [{
"id": 0, "id": 0,

View File

@ -115,6 +115,10 @@ OUTPUT: header.h
} }
OUTPUT: impl.cc OUTPUT: impl.cc
{ {
"includes": [{
"line": 1,
"resolved_path": "C:/Users/jacob/Desktop/superindex/indexer/tests/multi_file/header.h"
}],
"dependencies": ["C:/Users/jacob/Desktop/superindex/indexer/tests/multi_file/header.h"], "dependencies": ["C:/Users/jacob/Desktop/superindex/indexer/tests/multi_file/header.h"],
"funcs": [{ "funcs": [{
"id": 0, "id": 0,

View File

@ -17,6 +17,10 @@ OUTPUT: simple_header.h
} }
OUTPUT: simple_impl.cc OUTPUT: simple_impl.cc
{ {
"includes": [{
"line": 1,
"resolved_path": "C:/Users/jacob/Desktop/superindex/indexer/tests/multi_file/simple_header.h"
}],
"dependencies": ["C:/Users/jacob/Desktop/superindex/indexer/tests/multi_file/simple_header.h"], "dependencies": ["C:/Users/jacob/Desktop/superindex/indexer/tests/multi_file/simple_header.h"],
"funcs": [{ "funcs": [{
"id": 0, "id": 0,

View File

@ -26,6 +26,10 @@ OUTPUT: static.h
} }
OUTPUT: static.cc OUTPUT: static.cc
{ {
"includes": [{
"line": 1,
"resolved_path": "C:/Users/jacob/Desktop/superindex/indexer/tests/multi_file/static.h"
}],
"dependencies": ["C:/Users/jacob/Desktop/superindex/indexer/tests/multi_file/static.h"], "dependencies": ["C:/Users/jacob/Desktop/superindex/indexer/tests/multi_file/static.h"],
"types": [{ "types": [{
"id": 0, "id": 0,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long