mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-25 09:05:10 +00:00
wip
This commit is contained in:
parent
ca9918b8c4
commit
4ed00a3262
@ -67,6 +67,23 @@ std::vector<Type> Type::get_arguments() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<Type> Type::get_template_arguments() const {
|
||||||
|
/*
|
||||||
|
CINDEX_LINKAGE int clang_Type_getNumTemplateArguments(CXType T);
|
||||||
|
CINDEX_LINKAGE CXType clang_Type_getTemplateArgumentAsType(CXType T, unsigned i);
|
||||||
|
*/
|
||||||
|
|
||||||
|
int size = clang_Type_getNumTemplateArguments(cx_type);
|
||||||
|
assert(size >= 0);
|
||||||
|
if (size < 0)
|
||||||
|
return std::vector<Type>();
|
||||||
|
|
||||||
|
std::vector<Type> types(size);
|
||||||
|
for (int i = 0; i < size; ++i)
|
||||||
|
types.emplace_back(clang_Type_getTemplateArgumentAsType(cx_type, i));
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static_assert(sizeof(Cursor) == sizeof(CXCursor),
|
static_assert(sizeof(Cursor) == sizeof(CXCursor),
|
||||||
"Cursor must be the same size as CXCursor");
|
"Cursor must be the same size as CXCursor");
|
||||||
|
@ -30,6 +30,7 @@ public:
|
|||||||
|
|
||||||
Type get_return_type() const;
|
Type get_return_type() const;
|
||||||
std::vector<Type> get_arguments() const;
|
std::vector<Type> get_arguments() const;
|
||||||
|
std::vector<Type> get_template_arguments() const;
|
||||||
|
|
||||||
CXType cx_type;
|
CXType cx_type;
|
||||||
};
|
};
|
||||||
|
142
main.cpp
142
main.cpp
@ -516,7 +516,44 @@ std::optional<TypeId> ResolveDeclaringType(CXCursorKind kind, ParsingDatabase* d
|
|||||||
return declaring_type;
|
return declaring_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// |func_id| is the function definition that is currently being processed.
|
||||||
|
void InsertReference(ParsingDatabase* db, std::optional<FuncId> func_id, clang::Cursor referencer) {
|
||||||
|
clang::SourceLocation loc = referencer.get_source_location();
|
||||||
|
clang::Cursor referenced = referencer.get_referenced();
|
||||||
|
|
||||||
|
switch (referenced.get_kind()) {
|
||||||
|
case CXCursor_CXXMethod:
|
||||||
|
case CXCursor_FunctionDecl:
|
||||||
|
{
|
||||||
|
FuncId referenced_id = db->ToFuncId(referenced.get_usr());
|
||||||
|
FuncDef* referenced_def = db->Resolve(referenced_id);
|
||||||
|
|
||||||
|
if (func_id) {
|
||||||
|
FuncDef* func_def = db->Resolve(func_id.value());
|
||||||
|
func_def->callees.push_back(FuncRef(referenced_id, loc));
|
||||||
|
referenced_def->callers.push_back(FuncRef(func_id.value(), loc));
|
||||||
|
}
|
||||||
|
|
||||||
|
referenced_def->uses.push_back(loc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CXCursor_ParmDecl:
|
||||||
|
case CXCursor_FieldDecl:
|
||||||
|
case CXCursor_VarDecl:
|
||||||
|
{
|
||||||
|
VarId referenced_id = db->ToVarId(referenced.get_usr());
|
||||||
|
VarDef* referenced_def = db->Resolve(referenced_id);
|
||||||
|
|
||||||
|
referenced_def->uses.push_back(loc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
std::cerr << "Unhandled reference from \"" << referencer.ToString()
|
||||||
|
<< "\" to \"" << referenced.ToString() << "\"" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -568,7 +605,34 @@ void InsertTypeUsageAtLocation(ParsingDatabase* db, clang::Type type, const clan
|
|||||||
db->Resolve(type_id)->uses.push_back(location);
|
db->Resolve(type_id)->uses.push_back(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleVarDecl(ParsingDatabase* db, NamespaceStack* ns, clang::Cursor var, std::optional<TypeId> declaring_type) {
|
struct VarDeclVisitorParam {
|
||||||
|
ParsingDatabase* db;
|
||||||
|
std::optional<FuncId> func_id;
|
||||||
|
|
||||||
|
VarDeclVisitorParam(ParsingDatabase* db, std::optional<FuncId> func_id)
|
||||||
|
: db(db), func_id(func_id) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
clang::VisiterResult VarDeclVisitor(clang::Cursor cursor, clang::Cursor parent, VarDeclVisitorParam* param) {
|
||||||
|
switch (cursor.get_kind()) {
|
||||||
|
case CXCursor_TemplateRef:
|
||||||
|
case CXCursor_TypeRef:
|
||||||
|
InsertTypeUsageAtLocation(param->db, cursor.get_referenced().get_type(), cursor.get_source_location());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CXCursor_CallExpr:
|
||||||
|
InsertReference(param->db, param->func_id, cursor);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
std::cerr << "VarDeclVisitor unhandled " << cursor.ToString() << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return clang::VisiterResult::Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleVarDecl(ParsingDatabase* db, NamespaceStack* ns, clang::Cursor var, std::optional<TypeId> declaring_type, std::optional<FuncId> func_id) {
|
||||||
//Dump(var);
|
//Dump(var);
|
||||||
|
|
||||||
// Add a usage to the type of the variable.
|
// Add a usage to the type of the variable.
|
||||||
@ -613,51 +677,30 @@ void HandleVarDecl(ParsingDatabase* db, NamespaceStack* ns, clang::Cursor var, s
|
|||||||
// TODO: Figure out how to scan initializations properly. We probably need
|
// TODO: Figure out how to scan initializations properly. We probably need
|
||||||
// to scan for assignment statement, or definition+ctor.
|
// to scan for assignment statement, or definition+ctor.
|
||||||
var_def->initializations.push_back(var.get_source_location());
|
var_def->initializations.push_back(var.get_source_location());
|
||||||
|
clang::Type var_type = var.get_type().strip_qualifiers();
|
||||||
std::string var_type_usr = var.get_type().strip_qualifiers().get_usr();
|
std::string var_type_usr = var.get_type().strip_qualifiers().get_usr();
|
||||||
if (var_type_usr != "")
|
if (var_type_usr != "") {
|
||||||
var_def->variable_type = db->ToTypeId(var_type_usr);
|
var_def->variable_type = db->ToTypeId(var_type_usr);
|
||||||
}
|
/*
|
||||||
|
for (clang::Type template_param_type : var_type.get_template_arguments()) {
|
||||||
|
std::string usr = template_param_type.get_usr();
|
||||||
|
if (usr == "")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//TypeId template_param_id = db->ToTypeId(usr);
|
||||||
|
InsertTypeUsageAtLocation(db, template_param_type, var.get_source_location());
|
||||||
|
|
||||||
|
//std::cout << template_param_type.get_usr() << std::endl;
|
||||||
|
}*/
|
||||||
|
VarDeclVisitorParam varDeclVisitorParam(db, func_id);
|
||||||
// |func_id| is the function definition that is currently being processed.
|
var.VisitChildren(&VarDeclVisitor, &varDeclVisitorParam);
|
||||||
void InsertReference(ParsingDatabase* db, FuncId func_id, clang::Cursor referencer) {
|
|
||||||
clang::SourceLocation loc = referencer.get_source_location();
|
|
||||||
clang::Cursor referenced = referencer.get_referenced();
|
|
||||||
|
|
||||||
switch (referenced.get_kind()) {
|
|
||||||
case CXCursor_CXXMethod:
|
|
||||||
case CXCursor_FunctionDecl:
|
|
||||||
{
|
|
||||||
FuncId referenced_id = db->ToFuncId(referenced.get_usr());
|
|
||||||
FuncDef* referenced_def = db->Resolve(referenced_id);
|
|
||||||
FuncDef* func_def = db->Resolve(func_id);
|
|
||||||
|
|
||||||
func_def->callees.push_back(FuncRef(referenced_id, loc));
|
|
||||||
referenced_def->callers.push_back(FuncRef(func_id, loc));
|
|
||||||
referenced_def->uses.push_back(loc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case CXCursor_ParmDecl:
|
|
||||||
case CXCursor_FieldDecl:
|
|
||||||
case CXCursor_VarDecl:
|
|
||||||
{
|
|
||||||
VarId referenced_id = db->ToVarId(referenced.get_usr());
|
|
||||||
VarDef* referenced_def = db->Resolve(referenced_id);
|
|
||||||
|
|
||||||
referenced_def->uses.push_back(loc);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
std::cerr << "Unhandled reference from \"" << referencer.ToString()
|
|
||||||
<< "\" to \"" << referenced.ToString() << "\"" << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: Should we declare variables on prototypes? ie,
|
// TODO: Should we declare variables on prototypes? ie,
|
||||||
//
|
//
|
||||||
// foo(int* x);
|
// foo(int* x);
|
||||||
@ -698,8 +741,8 @@ clang::VisiterResult VisitFuncDefinition(clang::Cursor cursor, clang::Cursor par
|
|||||||
|
|
||||||
case CXCursor_VarDecl:
|
case CXCursor_VarDecl:
|
||||||
case CXCursor_ParmDecl:
|
case CXCursor_ParmDecl:
|
||||||
HandleVarDecl(param->db, param->ns, cursor, std::nullopt);
|
HandleVarDecl(param->db, param->ns, cursor, std::nullopt, param->func_id);
|
||||||
return clang::VisiterResult::Recurse;
|
return clang::VisiterResult::Continue;
|
||||||
|
|
||||||
case CXCursor_ReturnStmt:
|
case CXCursor_ReturnStmt:
|
||||||
return clang::VisiterResult::Recurse;
|
return clang::VisiterResult::Recurse;
|
||||||
@ -770,6 +813,12 @@ void HandleFunc(ParsingDatabase* db, NamespaceStack* ns, clang::Cursor func, std
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct UsingParam {
|
struct UsingParam {
|
||||||
ParsingDatabase* db;
|
ParsingDatabase* db;
|
||||||
TypeId active_type;
|
TypeId active_type;
|
||||||
@ -798,6 +847,10 @@ clang::VisiterResult VisitUsing(clang::Cursor cursor, clang::Cursor parent, Usin
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct ClassDeclParam {
|
struct ClassDeclParam {
|
||||||
ParsingDatabase* db;
|
ParsingDatabase* db;
|
||||||
NamespaceStack* ns;
|
NamespaceStack* ns;
|
||||||
@ -820,7 +873,7 @@ clang::VisiterResult VisitClassDecl(clang::Cursor cursor, clang::Cursor parent,
|
|||||||
|
|
||||||
case CXCursor_FieldDecl:
|
case CXCursor_FieldDecl:
|
||||||
case CXCursor_VarDecl:
|
case CXCursor_VarDecl:
|
||||||
HandleVarDecl(param->db, param->ns, cursor, param->active_type);
|
HandleVarDecl(param->db, param->ns, cursor, param->active_type, std::nullopt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -887,6 +940,7 @@ clang::VisiterResult VisitFile(clang::Cursor cursor, clang::Cursor parent, FileP
|
|||||||
HandleClassDecl(cursor, param->db, param->ns, true /*is_alias*/);
|
HandleClassDecl(cursor, param->db, param->ns, true /*is_alias*/);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CXCursor_ClassTemplate:
|
||||||
case CXCursor_StructDecl:
|
case CXCursor_StructDecl:
|
||||||
case CXCursor_ClassDecl:
|
case CXCursor_ClassDecl:
|
||||||
// TODO: Cleanup Handle* param order.
|
// TODO: Cleanup Handle* param order.
|
||||||
@ -899,7 +953,7 @@ clang::VisiterResult VisitFile(clang::Cursor cursor, clang::Cursor parent, FileP
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CXCursor_VarDecl:
|
case CXCursor_VarDecl:
|
||||||
HandleVarDecl(param->db, param->ns, cursor, std::nullopt);
|
HandleVarDecl(param->db, param->ns, cursor, std::nullopt, std::nullopt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1025,7 +1079,7 @@ void DiffDocuments(rapidjson::Document& expected, rapidjson::Document& actual) {
|
|||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
for (std::string path : GetFilesInFolder("tests")) {
|
for (std::string path : GetFilesInFolder("tests")) {
|
||||||
// TODO: Fix all existing tests.
|
// TODO: Fix all existing tests.
|
||||||
//if (path != "tests/usage/var_usage_func_parameter.cc") continue;
|
if (path != "tests/usage/type_usage_as_template_parameter.cc") continue;
|
||||||
|
|
||||||
// Parse expected output from the test, parse it into JSON document.
|
// Parse expected output from the test, parse it into JSON document.
|
||||||
std::string expected_output;
|
std::string expected_output;
|
||||||
|
@ -1,9 +1,88 @@
|
|||||||
// TODO: implement this test. It is meant to support unique_ptr<T>
|
template<typename T>
|
||||||
|
class unique_ptr {
|
||||||
|
public:
|
||||||
|
T value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
int x;
|
||||||
|
};
|
||||||
|
|
||||||
|
void foo() {
|
||||||
|
unique_ptr<Foo> f0;
|
||||||
|
unique_ptr<Foo> f1;
|
||||||
|
|
||||||
|
f0.value.x += 5;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
OUTPUT:
|
OUTPUT:
|
||||||
{
|
{
|
||||||
"types": [],
|
"types": [{
|
||||||
"functions": [],
|
"id": 0,
|
||||||
"variables": []
|
"usr": "c:@ST>1#T@unique_ptr",
|
||||||
|
"short_name": "unique_ptr",
|
||||||
|
"qualified_name": "unique_ptr",
|
||||||
|
"definition": "tests/usage/type_usage_as_template_parameter.cc:2:7",
|
||||||
|
"vars": [0]
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@S@Foo",
|
||||||
|
"short_name": "Foo",
|
||||||
|
"qualified_name": "Foo",
|
||||||
|
"definition": "tests/usage/type_usage_as_template_parameter.cc:7:8",
|
||||||
|
"vars": [1],
|
||||||
|
"uses": ["tests/usage/type_usage_as_template_parameter.cc:12:14", "tests/usage/type_usage_as_template_parameter.cc:13:14"]
|
||||||
|
}, {
|
||||||
|
"id": 2,
|
||||||
|
"usr": "c:@S@unique_ptr>#$@S@Foo",
|
||||||
|
"uses": ["tests/usage/type_usage_as_template_parameter.cc:12:19", "tests/usage/type_usage_as_template_parameter.cc:13:19"]
|
||||||
|
}],
|
||||||
|
"functions": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@F@foo#",
|
||||||
|
"short_name": "foo",
|
||||||
|
"qualified_name": "foo",
|
||||||
|
"definition": "tests/usage/type_usage_as_template_parameter.cc:11:6"
|
||||||
|
}],
|
||||||
|
"variables": [{
|
||||||
|
"id": 0,
|
||||||
|
"usr": "c:@ST>1#T@unique_ptr@FI@value",
|
||||||
|
"short_name": "value",
|
||||||
|
"qualified_name": "unique_ptr::value",
|
||||||
|
"declaration": "tests/usage/type_usage_as_template_parameter.cc:4:5",
|
||||||
|
"initializations": ["tests/usage/type_usage_as_template_parameter.cc:4:5"],
|
||||||
|
"declaring_type": 0
|
||||||
|
}, {
|
||||||
|
"id": 1,
|
||||||
|
"usr": "c:@S@Foo@FI@x",
|
||||||
|
"short_name": "x",
|
||||||
|
"qualified_name": "Foo::x",
|
||||||
|
"declaration": "tests/usage/type_usage_as_template_parameter.cc:8:7",
|
||||||
|
"initializations": ["tests/usage/type_usage_as_template_parameter.cc:8:7"],
|
||||||
|
"declaring_type": 1,
|
||||||
|
"uses": ["tests/usage/type_usage_as_template_parameter.cc:15:12"]
|
||||||
|
}, {
|
||||||
|
"id": 2,
|
||||||
|
"usr": "c:type_usage_as_template_parameter.cc@115@F@foo#@f0",
|
||||||
|
"short_name": "f0",
|
||||||
|
"qualified_name": "f0",
|
||||||
|
"declaration": "tests/usage/type_usage_as_template_parameter.cc:12:19",
|
||||||
|
"initializations": ["tests/usage/type_usage_as_template_parameter.cc:12:19"],
|
||||||
|
"variable_type": 2,
|
||||||
|
"uses": ["tests/usage/type_usage_as_template_parameter.cc:15:3"]
|
||||||
|
}, {
|
||||||
|
"id": 3,
|
||||||
|
"usr": "c:type_usage_as_template_parameter.cc@138@F@foo#@f1",
|
||||||
|
"short_name": "f1",
|
||||||
|
"qualified_name": "f1",
|
||||||
|
"declaration": "tests/usage/type_usage_as_template_parameter.cc:13:19",
|
||||||
|
"initializations": ["tests/usage/type_usage_as_template_parameter.cc:13:19"],
|
||||||
|
"variable_type": 2
|
||||||
|
}, {
|
||||||
|
"id": 4,
|
||||||
|
"usr": "c:@S@unique_ptr>#$@S@Foo@FI@value",
|
||||||
|
"uses": ["tests/usage/type_usage_as_template_parameter.cc:15:6"]
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
*/
|
*/
|
Loading…
Reference in New Issue
Block a user