Add initialization option index.builtin_types for indexing builtin types

Also deprecate enableComments in favor of index.comments

Make $cquery/vars work on variables (by obtaining their types first).
This is currently the only way to list instances of builtin types.
This commit is contained in:
Fangrui Song 2018-01-20 22:34:41 -08:00
parent 619ad11f9e
commit 6acea187c7
6 changed files with 67 additions and 28 deletions

View File

@ -119,18 +119,6 @@ CXCursorKind ClangCursor::get_kind() const {
return cx_cursor.kind;
}
ClangCursor ClangCursor::get_declaration() const {
ClangType type = get_type();
// auto x = new Foo() will not be deduced to |Foo| if we do not use the
// canonical type. However, a canonical type will look past typedefs so we
// will not accurately report variables on typedefs if we always do this.
if (type.cx_type.kind == CXType_Auto)
type = type.get_canonical();
return type.strip_qualifiers().get_declaration();
}
ClangType ClangCursor::get_type() const {
return ClangType(clang_getCursorType(cx_cursor));
}

View File

@ -51,7 +51,6 @@ class ClangCursor {
bool operator!=(const ClangCursor& rhs) const;
CXCursorKind get_kind() const;
ClangCursor get_declaration() const;
ClangType get_type() const;
std::string get_spelling() const;
Range get_spelling_range(CXFile* cx_file = nullptr) const;

View File

@ -91,18 +91,27 @@ struct Config {
// a function or method
bool enableSnippetInsertion = true;
// 0: no; 1: Doxygen comment markers; 2: -fparse-all-comments, which includes
// plain // /*
// TODO Deprecated in favor of index.comments
int enableComments = 0;
// If true, filter and sort completion response.
bool filterAndSortCompletionResponse = true;
struct Index {
bool builtin_types = false;
// 0: no; 1: Doxygen comment markers; 2: -fparse-all-comments, which includes
// plain // /*
int comments = 0;
};
Index index;
//// For debugging
// Dump AST after parsing if some pattern matches the source filename.
std::vector<std::string> dumpAST;
};
MAKE_REFLECT_STRUCT(Config::Index, builtin_types, comments);
MAKE_REFLECT_STRUCT(Config,
compilationDatabaseDirectory,
cacheDirectory,
@ -141,6 +150,8 @@ MAKE_REFLECT_STRUCT(Config,
enableComments,
index,
filterAndSortCompletionResponse,
dumpAST);

View File

@ -17,6 +17,9 @@
// TODO: See if we can use clang_indexLoc_getFileLocation to get a type ref on
// |Foobar| in DISALLOW_COPY(Foobar)
// TODO Global variable
bool g_index_builtin_types;
namespace {
constexpr bool kIndexStdDeclarations = true;
@ -393,13 +396,35 @@ bool IsFunctionCallContext(CXCursorKind kind) {
// (ie, Foo<A,B> => Foo<*,*>).
optional<IndexTypeId> ResolveToDeclarationType(IndexFile* db,
ClangCursor cursor) {
ClangCursor declaration = cursor.get_declaration();
declaration = declaration.template_specialization_to_template_definition();
// TODO optimize
std::string usr = declaration.get_usr();
if (usr.size())
return db->ToTypeId(declaration.get_usr_hash());
return nullopt;
ClangType type = cursor.get_type();
// auto x = new Foo() will not be deduced to |Foo| if we do not use the
// canonical type. However, a canonical type will look past typedefs so we
// will not accurately report variables on typedefs if we always do this.
if (type.cx_type.kind == CXType_Auto)
type = type.get_canonical();
type = type.strip_qualifiers();
if (CXType_FirstBuiltin <= type.cx_type.kind &&
type.cx_type.kind <= CXType_LastBuiltin) {
if (!g_index_builtin_types)
return nullopt;
return db->ToTypeId(type.cx_type.kind);
}
ClangCursor declaration =
ClangCursor(type.get_declaration())
.template_specialization_to_template_definition();
CXString cx_usr = clang_getCursorUSR(declaration.cx_cursor);
const char* str_usr = clang_getCString(cx_usr);
if (!str_usr || str_usr[0] == '\0') {
clang_disposeString(cx_usr);
return nullopt;
}
Usr usr = HashUsr(str_usr);
clang_disposeString(cx_usr);
return db->ToTypeId(usr);
}
void SetVarDetail(IndexVar* var,

View File

@ -25,11 +25,24 @@ struct CqueryVarsHandler : BaseMessageHandler<Ipc_CqueryVars> {
out.id = request->id;
for (const SymbolRef& ref :
FindSymbolsAtLocation(working_file, file, request->params.position)) {
if (ref.idx.kind == SymbolKind::Type) {
QueryType& type = db->types[ref.idx.idx];
std::vector<QueryLocation> locations =
ToQueryLocation(db, type.instances);
out.result = GetLsLocations(db, working_files, locations);
size_t id = ref.idx.idx;
switch (ref.idx.kind) {
default:
break;
case SymbolKind::Var: {
QueryVar& var = db->vars[id];
if (!var.def || !var.def->variable_type)
continue;
id = var.def->variable_type->id;
}
// fallthrough
case SymbolKind::Type: {
QueryType& type = db->types[id];
std::vector<QueryLocation> locations =
ToQueryLocation(db, type.instances);
out.result = GetLsLocations(db, working_files, locations);
break;
}
}
}
QueueManager::WriteStdout(IpcId::CqueryVars, out);

View File

@ -14,6 +14,7 @@
// TODO Cleanup global variables
extern std::string g_init_options;
extern bool g_index_builtin_types;
extern int g_enable_comments;
namespace {
@ -74,7 +75,9 @@ struct InitializeHandler : BaseMessageHandler<Ipc_InitializeRequest> {
}
}
}
g_enable_comments = config->enableComments;
g_index_builtin_types = config->index.builtin_types;
// TODO Remove enableComments
g_enable_comments = std::max(config->enableComments, config->index.comments);
// Check client version.
if (config->clientVersion.has_value() &&