mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-25 17:11:59 +00:00
update
This commit is contained in:
parent
358b4434c2
commit
ce4c2232d7
41
compilation_database_loader.cc
Normal file
41
compilation_database_loader.cc
Normal file
@ -0,0 +1,41 @@
|
||||
#include "compilation_database_loader.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <clang-c/CXCompilationDatabase.h>
|
||||
|
||||
#include "libclangmm/Utility.h"
|
||||
|
||||
std::vector<CompilationEntry> LoadCompilationEntriesFromDirectory(const std::string& project_directory) {
|
||||
CXCompilationDatabase_Error cx_db_load_error;
|
||||
CXCompilationDatabase cx_db = clang_CompilationDatabase_fromDirectory(project_directory.c_str(), &cx_db_load_error);
|
||||
if (cx_db_load_error == CXCompilationDatabase_CanNotLoadDatabase) {
|
||||
std::cerr << "[FATAL]: Unable to load compile_commands.json located at \"" << project_directory << "\"";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
CXCompileCommands cx_commands = clang_CompilationDatabase_getAllCompileCommands(cx_db);
|
||||
|
||||
unsigned int num_commands = clang_CompileCommands_getSize(cx_commands);
|
||||
std::vector<CompilationEntry> result;
|
||||
for (unsigned int i = 0; i < num_commands; i++) {
|
||||
CXCompileCommand cx_command = clang_CompileCommands_getCommand(cx_commands, i);
|
||||
CompilationEntry entry;
|
||||
|
||||
entry.directory = clang::ToString(clang_CompileCommand_getDirectory(cx_command));
|
||||
entry.filename = clang::ToString(clang_CompileCommand_getFilename(cx_command));
|
||||
|
||||
unsigned int num_args = clang_CompileCommand_getNumArgs(cx_command);
|
||||
entry.args.reserve(num_args);
|
||||
for (unsigned int j = 0; j < num_args; ++j) {
|
||||
entry.args.push_back(clang::ToString(clang_CompileCommand_getArg(cx_command, j)));
|
||||
}
|
||||
|
||||
result.push_back(entry);
|
||||
}
|
||||
|
||||
clang_CompileCommands_dispose(cx_commands);
|
||||
clang_CompilationDatabase_dispose(cx_db);
|
||||
|
||||
return result;
|
||||
}
|
12
compilation_database_loader.h
Normal file
12
compilation_database_loader.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct CompilationEntry {
|
||||
std::string directory;
|
||||
std::string filename;
|
||||
std::vector<std::string> args;
|
||||
};
|
||||
|
||||
std::vector<CompilationEntry> LoadCompilationEntriesFromDirectory(const std::string& project_directory);
|
1421
cxxopts.hpp
1421
cxxopts.hpp
File diff suppressed because it is too large
Load Diff
9
full_tests/simple_cross_reference/a.cc
Normal file
9
full_tests/simple_cross_reference/a.cc
Normal file
@ -0,0 +1,9 @@
|
||||
#include "a.h"
|
||||
|
||||
namespace {
|
||||
void LocalA() {
|
||||
Common();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void Common() {}
|
6
full_tests/simple_cross_reference/a.h
Normal file
6
full_tests/simple_cross_reference/a.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef A_H_
|
||||
#define A_H_
|
||||
|
||||
void Common();
|
||||
|
||||
#endif // A_H_
|
7
full_tests/simple_cross_reference/b.cc
Normal file
7
full_tests/simple_cross_reference/b.cc
Normal file
@ -0,0 +1,7 @@
|
||||
#include "a.h"
|
||||
|
||||
#if RANDOM_DEFINE
|
||||
static void LocaB() {
|
||||
Common();
|
||||
}
|
||||
#endif // RANDOM_DEFINE
|
12
full_tests/simple_cross_reference/compile_commands.json
Normal file
12
full_tests/simple_cross_reference/compile_commands.json
Normal file
@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"directory" : "full_tests/simple_cross_reference",
|
||||
"command" : "clang -c -o a.o a.cc",
|
||||
"file" : "full_tests/simple_cross_reference/a.cc"
|
||||
},
|
||||
{
|
||||
"directory" : "full_tests/simple_cross_reference",
|
||||
"command" : "clang -DRANDOM_DEFINE -c -o b.o b.cc",
|
||||
"file" : "full_tests/simple_cross_reference/b.cc"
|
||||
}
|
||||
]
|
@ -1,324 +1,4 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "libclangmm/clangmm.h"
|
||||
#include "libclangmm/Utility.h"
|
||||
|
||||
#include "bitfield.h"
|
||||
#include "utils.h"
|
||||
#include "optional.h"
|
||||
|
||||
#include <rapidjson/writer.h>
|
||||
#include <rapidjson/prettywriter.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
struct TypeDef;
|
||||
struct FuncDef;
|
||||
struct VarDef;
|
||||
|
||||
using FileId = int64_t;
|
||||
using namespace std::experimental;
|
||||
|
||||
|
||||
// TODO: Move off of this weird wrapper, use struct with custom wrappers
|
||||
// directly.
|
||||
BEGIN_BITFIELD_TYPE(Location, uint64_t)
|
||||
|
||||
ADD_BITFIELD_MEMBER(interesting, /*start:*/ 0, /*len:*/ 1); // 2 values
|
||||
ADD_BITFIELD_MEMBER(file_id, /*start:*/ 1, /*len:*/ 29); // 536,870,912 values
|
||||
ADD_BITFIELD_MEMBER(line, /*start:*/ 30, /*len:*/ 20); // 1,048,576 values
|
||||
ADD_BITFIELD_MEMBER(column, /*start:*/ 50, /*len:*/ 14); // 16,384 values
|
||||
|
||||
Location(bool interesting, FileId file_id, uint32_t line, uint32_t column) {
|
||||
this->interesting = interesting;
|
||||
this->file_id = file_id;
|
||||
this->line = line;
|
||||
this->column = column;
|
||||
}
|
||||
|
||||
std::string ToString() {
|
||||
// Output looks like this:
|
||||
//
|
||||
// *1:2:3
|
||||
//
|
||||
// * => interesting
|
||||
// 1 => file id
|
||||
// 2 => line
|
||||
// 3 => column
|
||||
|
||||
std::string result;
|
||||
if (interesting)
|
||||
result += '*';
|
||||
result += std::to_string(file_id);
|
||||
result += ':';
|
||||
result += std::to_string(line);
|
||||
result += ':';
|
||||
result += std::to_string(column);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Compare two Locations and check if they are equal. Ignores the value of
|
||||
// |interesting|.
|
||||
// operator== doesn't seem to work properly...
|
||||
bool IsEqualTo(const Location& o) {
|
||||
// When comparing, ignore the value of |interesting|.
|
||||
return (wrapper.value >> 1) == (o.wrapper.value >> 1);
|
||||
}
|
||||
|
||||
Location WithInteresting(bool interesting) {
|
||||
Location result = *this;
|
||||
result.interesting = interesting;
|
||||
return result;
|
||||
}
|
||||
|
||||
END_BITFIELD_TYPE()
|
||||
|
||||
struct FileDb {
|
||||
std::unordered_map<std::string, FileId> file_path_to_file_id;
|
||||
std::unordered_map<FileId, std::string> file_id_to_file_path;
|
||||
|
||||
FileDb() {
|
||||
// Reserve id 0 for unfound.
|
||||
file_path_to_file_id[""] = 0;
|
||||
file_id_to_file_path[0] = "";
|
||||
}
|
||||
|
||||
Location Resolve(const CXSourceLocation& cx_loc, bool interesting) {
|
||||
CXFile file;
|
||||
unsigned int line, column, offset;
|
||||
clang_getSpellingLocation(cx_loc, &file, &line, &column, &offset);
|
||||
|
||||
FileId file_id;
|
||||
if (file != nullptr) {
|
||||
std::string path = clang::ToString(clang_getFileName(file));
|
||||
|
||||
auto it = file_path_to_file_id.find(path);
|
||||
if (it != file_path_to_file_id.end()) {
|
||||
file_id = it->second;
|
||||
}
|
||||
else {
|
||||
file_id = file_path_to_file_id.size();
|
||||
file_path_to_file_id[path] = file_id;
|
||||
file_id_to_file_path[file_id] = path;
|
||||
}
|
||||
}
|
||||
|
||||
return Location(interesting, file_id, line, column);
|
||||
}
|
||||
|
||||
Location Resolve(const CXIdxLoc& cx_idx_loc, bool interesting) {
|
||||
CXSourceLocation cx_loc = clang_indexLoc_getCXSourceLocation(cx_idx_loc);
|
||||
return Resolve(cx_loc, interesting);
|
||||
}
|
||||
|
||||
Location Resolve(const CXCursor& cx_cursor, bool interesting) {
|
||||
return Resolve(clang_getCursorLocation(cx_cursor), interesting);
|
||||
}
|
||||
|
||||
Location Resolve(const clang::Cursor& cursor, bool interesting) {
|
||||
return Resolve(cursor.cx_cursor, interesting);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct LocalId {
|
||||
uint64_t local_id;
|
||||
|
||||
LocalId() : local_id(0) {} // Needed for containers. Do not use directly.
|
||||
explicit LocalId(uint64_t local_id) : local_id(local_id) {}
|
||||
|
||||
bool operator==(const LocalId<T>& other) {
|
||||
return local_id == other.local_id;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool operator==(const LocalId<T>& a, const LocalId<T>& b) {
|
||||
return a.local_id == b.local_id;
|
||||
}
|
||||
|
||||
using TypeId = LocalId<TypeDef>;
|
||||
using FuncId = LocalId<FuncDef>;
|
||||
using VarId = LocalId<VarDef>;
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Ref {
|
||||
LocalId<T> id;
|
||||
Location loc;
|
||||
|
||||
Ref(LocalId<T> id, Location loc) : id(id), loc(loc) {}
|
||||
};
|
||||
using TypeRef = Ref<TypeDef>;
|
||||
using FuncRef = Ref<FuncDef>;
|
||||
using VarRef = Ref<VarDef>;
|
||||
|
||||
|
||||
// TODO: skip as much forward-processing as possible when |is_system_def| is
|
||||
// set to false.
|
||||
// TODO: Either eliminate the defs created as a by-product of cross-referencing,
|
||||
// or do not emit things we don't have definitions for.
|
||||
|
||||
struct TypeDef {
|
||||
bool is_system_def = false;
|
||||
|
||||
// General metadata.
|
||||
TypeId id;
|
||||
std::string usr;
|
||||
std::string short_name;
|
||||
std::string qualified_name;
|
||||
|
||||
// While a class/type can technically have a separate declaration/definition,
|
||||
// it doesn't really happen in practice. The declaration never contains
|
||||
// comments or insightful information. The user always wants to jump from
|
||||
// the declaration to the definition - never the other way around like in
|
||||
// functions and (less often) variables.
|
||||
//
|
||||
// It's also difficult to identify a `class Foo;` statement with the clang
|
||||
// indexer API (it's doable using cursor AST traversal), so we don't bother
|
||||
// supporting the feature.
|
||||
optional<Location> definition;
|
||||
|
||||
// If set, then this is the same underlying type as the given value (ie, this
|
||||
// type comes from a using or typedef statement).
|
||||
optional<TypeId> alias_of;
|
||||
|
||||
// Immediate parent and immediate derived types.
|
||||
std::vector<TypeId> parents;
|
||||
std::vector<TypeId> derived;
|
||||
|
||||
// Types, functions, and variables defined in this type.
|
||||
std::vector<TypeId> types;
|
||||
std::vector<FuncId> funcs;
|
||||
std::vector<VarId> vars;
|
||||
|
||||
// Every usage, useful for things like renames.
|
||||
// NOTE: Do not insert directly! Use AddUsage instead.
|
||||
std::vector<Location> uses;
|
||||
|
||||
TypeDef(TypeId id, const std::string& usr) : id(id), usr(usr) {
|
||||
assert(usr.size() > 0);
|
||||
//std::cout << "Creating type with usr " << usr << std::endl;
|
||||
}
|
||||
|
||||
void AddUsage(Location loc, bool insert_if_not_present = true) {
|
||||
if (is_system_def)
|
||||
return;
|
||||
|
||||
for (int i = uses.size() - 1; i >= 0; --i) {
|
||||
if (uses[i].IsEqualTo(loc)) {
|
||||
if (loc.interesting)
|
||||
uses[i].interesting = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (insert_if_not_present)
|
||||
uses.push_back(loc);
|
||||
}
|
||||
};
|
||||
|
||||
struct FuncDef {
|
||||
bool is_system_def = false;
|
||||
|
||||
// General metadata.
|
||||
FuncId id;
|
||||
std::string usr;
|
||||
std::string short_name;
|
||||
std::string qualified_name;
|
||||
optional<Location> declaration;
|
||||
optional<Location> definition;
|
||||
|
||||
// Type which declares this one (ie, it is a method)
|
||||
optional<TypeId> declaring_type;
|
||||
// Method this method overrides.
|
||||
optional<FuncId> base;
|
||||
// Methods which directly override this one.
|
||||
std::vector<FuncId> derived;
|
||||
|
||||
// Local variables defined in this function.
|
||||
std::vector<VarId> locals;
|
||||
|
||||
// Functions which call this one.
|
||||
// TODO: Functions can get called outside of just functions - for example,
|
||||
// they can get called in static context (maybe redirect to main?)
|
||||
// or in class initializer list (redirect to class ctor?)
|
||||
// - Right now those usages will not get listed here (but they should be
|
||||
// inside of all_uses).
|
||||
std::vector<FuncRef> callers;
|
||||
// Functions that this function calls.
|
||||
std::vector<FuncRef> callees;
|
||||
|
||||
// All usages. For interesting usages, see callees.
|
||||
std::vector<Location> uses;
|
||||
|
||||
FuncDef(FuncId id, const std::string& usr) : id(id), usr(usr) {
|
||||
assert(usr.size() > 0);
|
||||
}
|
||||
};
|
||||
|
||||
struct VarDef {
|
||||
bool is_system_def = false;
|
||||
|
||||
// General metadata.
|
||||
VarId id;
|
||||
std::string usr;
|
||||
std::string short_name;
|
||||
std::string qualified_name;
|
||||
optional<Location> declaration;
|
||||
// TODO: definitions should be a list of locations, since there can be more
|
||||
// than one.
|
||||
optional<Location> definition;
|
||||
|
||||
// Type of the variable.
|
||||
optional<TypeId> variable_type;
|
||||
|
||||
// Type which declares this one (ie, it is a method)
|
||||
optional<TypeId> declaring_type;
|
||||
|
||||
// Usages.
|
||||
std::vector<Location> uses;
|
||||
|
||||
VarDef(VarId id, const std::string& usr) : id(id), usr(usr) {
|
||||
assert(usr.size() > 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ParsingDatabase {
|
||||
// NOTE: Every Id is resolved to a file_id of 0. The correct file_id needs
|
||||
// to get fixed up when inserting into the real db.
|
||||
std::unordered_map<std::string, TypeId> usr_to_type_id;
|
||||
std::unordered_map<std::string, FuncId> usr_to_func_id;
|
||||
std::unordered_map<std::string, VarId> usr_to_var_id;
|
||||
|
||||
std::vector<TypeDef> types;
|
||||
std::vector<FuncDef> funcs;
|
||||
std::vector<VarDef> vars;
|
||||
|
||||
FileDb file_db;
|
||||
|
||||
ParsingDatabase();
|
||||
|
||||
TypeId ToTypeId(const std::string& usr);
|
||||
FuncId ToFuncId(const std::string& usr);
|
||||
VarId ToVarId(const std::string& usr);
|
||||
TypeId ToTypeId(const CXCursor& usr);
|
||||
FuncId ToFuncId(const CXCursor& usr);
|
||||
VarId ToVarId(const CXCursor& usr);
|
||||
|
||||
TypeDef* Resolve(TypeId id);
|
||||
FuncDef* Resolve(FuncId id);
|
||||
VarDef* Resolve(VarId id);
|
||||
|
||||
std::string ToString();
|
||||
};
|
||||
#include "indexer.h"
|
||||
|
||||
ParsingDatabase::ParsingDatabase() {}
|
||||
|
||||
@ -1284,9 +964,7 @@ void indexEntityReference(CXClientData client_data, const CXIdxEntityRefInfo* re
|
||||
static bool DUMP_AST = true;
|
||||
|
||||
|
||||
ParsingDatabase Parse(std::string filename) {
|
||||
std::vector<std::string> args;
|
||||
|
||||
ParsingDatabase Parse(std::string filename, std::vector<std::string> args) {
|
||||
clang::Index index(0 /*excludeDeclarationsFromPCH*/, 0 /*displayDiagnostics*/);
|
||||
clang::TranslationUnit tu(index, filename, args);
|
||||
|
||||
@ -1412,6 +1090,8 @@ void WriteToFile(const std::string& filename, const std::string& content) {
|
||||
}
|
||||
|
||||
int mai2n(int argc, char** argv) {
|
||||
// TODO: Assert that we need to be on clang >= 3.9.1
|
||||
|
||||
/*
|
||||
ParsingDatabase db = Parse("tests/vars/function_local.cc");
|
||||
std::cout << std::endl << "== Database ==" << std::endl;
|
||||
@ -1448,7 +1128,7 @@ int mai2n(int argc, char** argv) {
|
||||
|
||||
// Run test.
|
||||
std::cout << "[START] " << path << std::endl;
|
||||
ParsingDatabase db = Parse(path);
|
||||
ParsingDatabase db = Parse(path, {});
|
||||
std::string actual_output = db.ToString();
|
||||
|
||||
//WriteToFile("output.json", actual_output);
|
325
indexer.h
Normal file
325
indexer.h
Normal file
@ -0,0 +1,325 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "libclangmm/clangmm.h"
|
||||
#include "libclangmm/Utility.h"
|
||||
|
||||
#include "bitfield.h"
|
||||
#include "utils.h"
|
||||
#include "optional.h"
|
||||
|
||||
#include <rapidjson/writer.h>
|
||||
#include <rapidjson/prettywriter.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
struct TypeDef;
|
||||
struct FuncDef;
|
||||
struct VarDef;
|
||||
|
||||
using FileId = int64_t;
|
||||
using namespace std::experimental;
|
||||
|
||||
|
||||
// TODO: Move off of this weird wrapper, use struct with custom wrappers
|
||||
// directly.
|
||||
BEGIN_BITFIELD_TYPE(Location, uint64_t)
|
||||
|
||||
ADD_BITFIELD_MEMBER(interesting, /*start:*/ 0, /*len:*/ 1); // 2 values
|
||||
ADD_BITFIELD_MEMBER(file_id, /*start:*/ 1, /*len:*/ 29); // 536,870,912 values
|
||||
ADD_BITFIELD_MEMBER(line, /*start:*/ 30, /*len:*/ 20); // 1,048,576 values
|
||||
ADD_BITFIELD_MEMBER(column, /*start:*/ 50, /*len:*/ 14); // 16,384 values
|
||||
|
||||
Location(bool interesting, FileId file_id, uint32_t line, uint32_t column) {
|
||||
this->interesting = interesting;
|
||||
this->file_id = file_id;
|
||||
this->line = line;
|
||||
this->column = column;
|
||||
}
|
||||
|
||||
std::string ToString() {
|
||||
// Output looks like this:
|
||||
//
|
||||
// *1:2:3
|
||||
//
|
||||
// * => interesting
|
||||
// 1 => file id
|
||||
// 2 => line
|
||||
// 3 => column
|
||||
|
||||
std::string result;
|
||||
if (interesting)
|
||||
result += '*';
|
||||
result += std::to_string(file_id);
|
||||
result += ':';
|
||||
result += std::to_string(line);
|
||||
result += ':';
|
||||
result += std::to_string(column);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Compare two Locations and check if they are equal. Ignores the value of
|
||||
// |interesting|.
|
||||
// operator== doesn't seem to work properly...
|
||||
bool IsEqualTo(const Location& o) {
|
||||
// When comparing, ignore the value of |interesting|.
|
||||
return (wrapper.value >> 1) == (o.wrapper.value >> 1);
|
||||
}
|
||||
|
||||
Location WithInteresting(bool interesting) {
|
||||
Location result = *this;
|
||||
result.interesting = interesting;
|
||||
return result;
|
||||
}
|
||||
|
||||
END_BITFIELD_TYPE()
|
||||
|
||||
struct FileDb {
|
||||
std::unordered_map<std::string, FileId> file_path_to_file_id;
|
||||
std::unordered_map<FileId, std::string> file_id_to_file_path;
|
||||
|
||||
FileDb() {
|
||||
// Reserve id 0 for unfound.
|
||||
file_path_to_file_id[""] = 0;
|
||||
file_id_to_file_path[0] = "";
|
||||
}
|
||||
|
||||
Location Resolve(const CXSourceLocation& cx_loc, bool interesting) {
|
||||
CXFile file;
|
||||
unsigned int line, column, offset;
|
||||
clang_getSpellingLocation(cx_loc, &file, &line, &column, &offset);
|
||||
|
||||
FileId file_id;
|
||||
if (file != nullptr) {
|
||||
std::string path = clang::ToString(clang_getFileName(file));
|
||||
|
||||
auto it = file_path_to_file_id.find(path);
|
||||
if (it != file_path_to_file_id.end()) {
|
||||
file_id = it->second;
|
||||
}
|
||||
else {
|
||||
file_id = file_path_to_file_id.size();
|
||||
file_path_to_file_id[path] = file_id;
|
||||
file_id_to_file_path[file_id] = path;
|
||||
}
|
||||
}
|
||||
|
||||
return Location(interesting, file_id, line, column);
|
||||
}
|
||||
|
||||
Location Resolve(const CXIdxLoc& cx_idx_loc, bool interesting) {
|
||||
CXSourceLocation cx_loc = clang_indexLoc_getCXSourceLocation(cx_idx_loc);
|
||||
return Resolve(cx_loc, interesting);
|
||||
}
|
||||
|
||||
Location Resolve(const CXCursor& cx_cursor, bool interesting) {
|
||||
return Resolve(clang_getCursorLocation(cx_cursor), interesting);
|
||||
}
|
||||
|
||||
Location Resolve(const clang::Cursor& cursor, bool interesting) {
|
||||
return Resolve(cursor.cx_cursor, interesting);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct LocalId {
|
||||
uint64_t local_id;
|
||||
|
||||
LocalId() : local_id(0) {} // Needed for containers. Do not use directly.
|
||||
explicit LocalId(uint64_t local_id) : local_id(local_id) {}
|
||||
|
||||
bool operator==(const LocalId<T>& other) {
|
||||
return local_id == other.local_id;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
bool operator==(const LocalId<T>& a, const LocalId<T>& b) {
|
||||
return a.local_id == b.local_id;
|
||||
}
|
||||
|
||||
using TypeId = LocalId<TypeDef>;
|
||||
using FuncId = LocalId<FuncDef>;
|
||||
using VarId = LocalId<VarDef>;
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Ref {
|
||||
LocalId<T> id;
|
||||
Location loc;
|
||||
|
||||
Ref(LocalId<T> id, Location loc) : id(id), loc(loc) {}
|
||||
};
|
||||
using TypeRef = Ref<TypeDef>;
|
||||
using FuncRef = Ref<FuncDef>;
|
||||
using VarRef = Ref<VarDef>;
|
||||
|
||||
|
||||
// TODO: skip as much forward-processing as possible when |is_system_def| is
|
||||
// set to false.
|
||||
// TODO: Either eliminate the defs created as a by-product of cross-referencing,
|
||||
// or do not emit things we don't have definitions for.
|
||||
|
||||
struct TypeDef {
|
||||
bool is_system_def = false;
|
||||
|
||||
// General metadata.
|
||||
TypeId id;
|
||||
std::string usr;
|
||||
std::string short_name;
|
||||
std::string qualified_name;
|
||||
|
||||
// While a class/type can technically have a separate declaration/definition,
|
||||
// it doesn't really happen in practice. The declaration never contains
|
||||
// comments or insightful information. The user always wants to jump from
|
||||
// the declaration to the definition - never the other way around like in
|
||||
// functions and (less often) variables.
|
||||
//
|
||||
// It's also difficult to identify a `class Foo;` statement with the clang
|
||||
// indexer API (it's doable using cursor AST traversal), so we don't bother
|
||||
// supporting the feature.
|
||||
optional<Location> definition;
|
||||
|
||||
// If set, then this is the same underlying type as the given value (ie, this
|
||||
// type comes from a using or typedef statement).
|
||||
optional<TypeId> alias_of;
|
||||
|
||||
// Immediate parent and immediate derived types.
|
||||
std::vector<TypeId> parents;
|
||||
std::vector<TypeId> derived;
|
||||
|
||||
// Types, functions, and variables defined in this type.
|
||||
std::vector<TypeId> types;
|
||||
std::vector<FuncId> funcs;
|
||||
std::vector<VarId> vars;
|
||||
|
||||
// Every usage, useful for things like renames.
|
||||
// NOTE: Do not insert directly! Use AddUsage instead.
|
||||
std::vector<Location> uses;
|
||||
|
||||
TypeDef(TypeId id, const std::string& usr) : id(id), usr(usr) {
|
||||
assert(usr.size() > 0);
|
||||
//std::cout << "Creating type with usr " << usr << std::endl;
|
||||
}
|
||||
|
||||
void AddUsage(Location loc, bool insert_if_not_present = true) {
|
||||
if (is_system_def)
|
||||
return;
|
||||
|
||||
for (int i = uses.size() - 1; i >= 0; --i) {
|
||||
if (uses[i].IsEqualTo(loc)) {
|
||||
if (loc.interesting)
|
||||
uses[i].interesting = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (insert_if_not_present)
|
||||
uses.push_back(loc);
|
||||
}
|
||||
};
|
||||
|
||||
struct FuncDef {
|
||||
bool is_system_def = false;
|
||||
|
||||
// General metadata.
|
||||
FuncId id;
|
||||
std::string usr;
|
||||
std::string short_name;
|
||||
std::string qualified_name;
|
||||
optional<Location> declaration;
|
||||
optional<Location> definition;
|
||||
|
||||
// Type which declares this one (ie, it is a method)
|
||||
optional<TypeId> declaring_type;
|
||||
// Method this method overrides.
|
||||
optional<FuncId> base;
|
||||
// Methods which directly override this one.
|
||||
std::vector<FuncId> derived;
|
||||
|
||||
// Local variables defined in this function.
|
||||
std::vector<VarId> locals;
|
||||
|
||||
// Functions which call this one.
|
||||
// TODO: Functions can get called outside of just functions - for example,
|
||||
// they can get called in static context (maybe redirect to main?)
|
||||
// or in class initializer list (redirect to class ctor?)
|
||||
// - Right now those usages will not get listed here (but they should be
|
||||
// inside of all_uses).
|
||||
std::vector<FuncRef> callers;
|
||||
// Functions that this function calls.
|
||||
std::vector<FuncRef> callees;
|
||||
|
||||
// All usages. For interesting usages, see callees.
|
||||
std::vector<Location> uses;
|
||||
|
||||
FuncDef(FuncId id, const std::string& usr) : id(id), usr(usr) {
|
||||
assert(usr.size() > 0);
|
||||
}
|
||||
};
|
||||
|
||||
struct VarDef {
|
||||
bool is_system_def = false;
|
||||
|
||||
// General metadata.
|
||||
VarId id;
|
||||
std::string usr;
|
||||
std::string short_name;
|
||||
std::string qualified_name;
|
||||
optional<Location> declaration;
|
||||
// TODO: definitions should be a list of locations, since there can be more
|
||||
// than one.
|
||||
optional<Location> definition;
|
||||
|
||||
// Type of the variable.
|
||||
optional<TypeId> variable_type;
|
||||
|
||||
// Type which declares this one (ie, it is a method)
|
||||
optional<TypeId> declaring_type;
|
||||
|
||||
// Usages.
|
||||
std::vector<Location> uses;
|
||||
|
||||
VarDef(VarId id, const std::string& usr) : id(id), usr(usr) {
|
||||
assert(usr.size() > 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ParsingDatabase {
|
||||
// NOTE: Every Id is resolved to a file_id of 0. The correct file_id needs
|
||||
// to get fixed up when inserting into the real db.
|
||||
std::unordered_map<std::string, TypeId> usr_to_type_id;
|
||||
std::unordered_map<std::string, FuncId> usr_to_func_id;
|
||||
std::unordered_map<std::string, VarId> usr_to_var_id;
|
||||
|
||||
std::vector<TypeDef> types;
|
||||
std::vector<FuncDef> funcs;
|
||||
std::vector<VarDef> vars;
|
||||
|
||||
FileDb file_db;
|
||||
|
||||
ParsingDatabase();
|
||||
|
||||
TypeId ToTypeId(const std::string& usr);
|
||||
FuncId ToFuncId(const std::string& usr);
|
||||
VarId ToVarId(const std::string& usr);
|
||||
TypeId ToTypeId(const CXCursor& usr);
|
||||
FuncId ToFuncId(const CXCursor& usr);
|
||||
VarId ToVarId(const CXCursor& usr);
|
||||
|
||||
TypeDef* Resolve(TypeId id);
|
||||
FuncDef* Resolve(FuncId id);
|
||||
VarDef* Resolve(VarId id);
|
||||
|
||||
std::string ToString();
|
||||
};
|
||||
|
||||
ParsingDatabase Parse(std::string filename, std::vector<std::string> args);
|
19
indexer.vcxproj.user
Normal file
19
indexer.vcxproj.user
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LocalDebuggerCommandArguments>--project C:\Users\jacob\Desktop\superindex\indexer\full_tests\simple_cross_reference</LocalDebuggerCommandArguments>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LocalDebuggerCommandArguments>--project C:\Users\jacob\Desktop\superindex\indexer\full_tests\simple_cross_reference</LocalDebuggerCommandArguments>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LocalDebuggerCommandArguments>--project C:\Users\jacob\Desktop\superindex\indexer\full_tests\simple_cross_reference</LocalDebuggerCommandArguments>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LocalDebuggerCommandArguments>--project C:\Users\jacob\Desktop\superindex\indexer\full_tests\simple_cross_reference</LocalDebuggerCommandArguments>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
</Project>
|
@ -1,11 +1,14 @@
|
||||
#include "CompilationDatabase.h"
|
||||
#include <exception>
|
||||
|
||||
clang::CompilationDatabase::CompilationDatabase(const std::string &project_path) {
|
||||
#include <iostream>
|
||||
|
||||
clang::CompilationDatabase::CompilationDatabase(const std::string& project_path) {
|
||||
CXCompilationDatabase_Error error;
|
||||
cx_db = clang_CompilationDatabase_fromDirectory(project_path.c_str(), &error);
|
||||
if(error) {
|
||||
//TODO: compile_commands.json is missing, create it?
|
||||
if (error == CXCompilationDatabase_CanNotLoadDatabase) {
|
||||
std::cerr << "[FATAL]: Unable to load compile_commands.json located at \""
|
||||
<< project_path << "\"";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,20 @@
|
||||
#ifndef COMPILATIONDATABASE_H_
|
||||
#define COMPILATIONDATABASE_H_
|
||||
#pragma once
|
||||
|
||||
#include <clang-c/CXCompilationDatabase.h>
|
||||
#include <clang-c/Index.h>
|
||||
#include <string>
|
||||
#include <clang-c/CXCompilationDatabase.h>
|
||||
|
||||
namespace clang {
|
||||
class CompilationDatabase {
|
||||
public:
|
||||
explicit CompilationDatabase(const std::string &project_path);
|
||||
~CompilationDatabase();
|
||||
|
||||
CXCompilationDatabase cx_db;
|
||||
};
|
||||
struct CompilationCommand {
|
||||
std::string path;
|
||||
std::string args;
|
||||
};
|
||||
|
||||
class CompilationDatabase {
|
||||
public:
|
||||
explicit CompilationDatabase(const std::string &project_path);
|
||||
~CompilationDatabase();
|
||||
|
||||
CXCompilationDatabase cx_db;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // COMPILATIONDATABASE_H_
|
||||
|
@ -2,20 +2,27 @@
|
||||
#include "CompileCommands.h"
|
||||
#include "Utility.h"
|
||||
|
||||
std::string clang::CompileCommand::get_command() {
|
||||
std::string res;
|
||||
unsigned N = clang_CompileCommand_getNumArgs(cx_command);
|
||||
for (unsigned i = 0; i < N; i++) {
|
||||
res += ToString(clang_CompileCommand_getArg(cx_command, i));
|
||||
}
|
||||
return res;
|
||||
namespace clang {
|
||||
|
||||
CompileCommand::CompileCommand(const CXCompileCommand& command)
|
||||
: cx_command(command) {};
|
||||
|
||||
std::string CompileCommand::get_command() const {
|
||||
std::string result;
|
||||
unsigned int num_args = clang_CompileCommand_getNumArgs(cx_command);
|
||||
for (unsigned int i = 0; i < num_args; i++)
|
||||
result += ToString(clang_CompileCommand_getArg(cx_command, i));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> clang::CompileCommand::get_command_as_args() {
|
||||
unsigned N = clang_CompileCommand_getNumArgs(cx_command);
|
||||
std::vector<std::string> res(N);
|
||||
for (unsigned i = 0; i < N; i++) {
|
||||
res[i] = ToString(clang_CompileCommand_getArg(cx_command, i));
|
||||
}
|
||||
return res;
|
||||
std::vector<std::string> CompileCommand::get_command_as_args() const {
|
||||
unsigned num_args = clang_CompileCommand_getNumArgs(cx_command);
|
||||
std::vector<std::string> result(num_args);
|
||||
for (unsigned i = 0; i < num_args; i++)
|
||||
result[i] = ToString(clang_CompileCommand_getArg(cx_command, i));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace clang
|
@ -1,17 +1,16 @@
|
||||
#ifndef COMPILECOMMAND_H_
|
||||
#define COMPILECOMMAND_H_
|
||||
#pragma once
|
||||
|
||||
#include <clang-c/CXCompilationDatabase.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
class CompileCommand {
|
||||
public:
|
||||
CompileCommand(const CXCompileCommand& cx_command) : cx_command(cx_command) {};
|
||||
std::string get_command();
|
||||
std::vector<std::string> get_command_as_args();
|
||||
class CompileCommand {
|
||||
public:
|
||||
CompileCommand(const CXCompileCommand& cx_command);
|
||||
std::string get_command() const;
|
||||
std::vector<std::string> get_command_as_args() const;
|
||||
|
||||
CXCompileCommand cx_command;
|
||||
};
|
||||
CXCompileCommand cx_command;
|
||||
};
|
||||
}
|
||||
#endif // COMPILECOMMAND_H_
|
||||
|
@ -1,10 +1,10 @@
|
||||
#include "CompileCommands.h"
|
||||
|
||||
clang::CompileCommands::CompileCommands(const std::string &filename, CompilationDatabase &db) {
|
||||
clang::CompileCommands::CompileCommands(const CompilationDatabase& db) {
|
||||
cx_commands =
|
||||
clang_CompilationDatabase_getCompileCommands(db.cx_db, filename.c_str());
|
||||
if(clang_CompileCommands_getSize(cx_commands)==0)
|
||||
cx_commands = clang_CompilationDatabase_getAllCompileCommands(db.cx_db);
|
||||
clang_CompilationDatabase_getAllCompileCommands(db.cx_db);
|
||||
//if (clang_CompileCommands_getSize(cx_commands) == 0)
|
||||
// cx_commands = clang_CompilationDatabase_getAllCompileCommands(db.cx_db);
|
||||
}
|
||||
|
||||
clang::CompileCommands::~CompileCommands() {
|
||||
@ -15,7 +15,8 @@ std::vector<clang::CompileCommand> clang::CompileCommands::get_commands() {
|
||||
unsigned N = clang_CompileCommands_getSize(cx_commands);
|
||||
std::vector<CompileCommand> res;
|
||||
for (unsigned i = 0; i < N; i++) {
|
||||
res.emplace_back(clang_CompileCommands_getCommand(cx_commands, i));
|
||||
CXCompileCommand command = clang_CompileCommands_getCommand(cx_commands, i);
|
||||
res.push_back(command);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -1,19 +1,19 @@
|
||||
#ifndef COMPILECOMMANDS_H_
|
||||
#define COMPILECOMMANDS_H_
|
||||
#include "CompilationDatabase.h"
|
||||
#include "CompileCommand.h"
|
||||
#include <clang-c/CXCompilationDatabase.h>
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <clang-c/CXCompilationDatabase.h>
|
||||
|
||||
#include "CompilationDatabase.h"
|
||||
#include "CompileCommand.h"
|
||||
|
||||
namespace clang {
|
||||
class CompileCommands {
|
||||
public:
|
||||
CompileCommands(const std::string &filename, CompilationDatabase &db);
|
||||
std::vector<CompileCommand> get_commands();
|
||||
~CompileCommands();
|
||||
class CompileCommands {
|
||||
public:
|
||||
CompileCommands(const CompilationDatabase& db);
|
||||
std::vector<CompileCommand> get_commands();
|
||||
~CompileCommands();
|
||||
|
||||
CXCompileCommands cx_commands;
|
||||
};
|
||||
CXCompileCommands cx_commands;
|
||||
};
|
||||
}
|
||||
#endif // COMPILECOMMANDS_H_
|
||||
|
@ -211,6 +211,7 @@ std::string Cursor::get_type_description() const {
|
||||
return spelling;
|
||||
}
|
||||
|
||||
#if false
|
||||
std::string Cursor::evaluate() const {
|
||||
CXEvalResult eval = clang_Cursor_Evaluate(cx_cursor);
|
||||
|
||||
@ -293,6 +294,7 @@ std::string Cursor::evaluate() const {
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string Cursor::get_comments() const {
|
||||
Cursor referenced = get_referenced();
|
||||
|
@ -67,7 +67,7 @@ public:
|
||||
std::vector<Cursor> get_arguments() const;
|
||||
bool is_valid_kind() const;
|
||||
|
||||
std::string evaluate() const;
|
||||
//std::string evaluate() const;
|
||||
|
||||
std::string get_type_description() const;
|
||||
std::string get_comments() const;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "Utility.h"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
|
||||
@ -20,20 +21,24 @@ TranslationUnit::TranslationUnit(Index &index, const std::string &file_path,
|
||||
files[0].Contents = buffer.c_str();
|
||||
files[0].Length = buffer.size();
|
||||
|
||||
cx_tu = clang_parseTranslationUnit(index.cx_index, file_path.c_str(), args.data(),
|
||||
args.size(), files, 1, flags);
|
||||
CXErrorCode error_code = clang_parseTranslationUnit2(
|
||||
index.cx_index, file_path.c_str(), args.data(), args.size(), files, 1, flags, &cx_tu);
|
||||
assert(!error_code);
|
||||
}
|
||||
|
||||
TranslationUnit::TranslationUnit(Index &index, const std::string &file_path,
|
||||
const std::vector<std::string> &command_line_args,
|
||||
unsigned flags) {
|
||||
const std::vector<std::string> &command_line_args, unsigned flags) {
|
||||
|
||||
// TODO: only push defines for the time being. Might need to pass more flags.
|
||||
std::vector<const char*> args;
|
||||
for (auto &a : command_line_args) {
|
||||
args.push_back(a.c_str());
|
||||
for (const std::string& a : command_line_args) {
|
||||
if (a.size() >= 2 && a[0] == '-' && a[1] == 'D')
|
||||
args.push_back(a.c_str());
|
||||
}
|
||||
|
||||
cx_tu = clang_parseTranslationUnit(index.cx_index, file_path.c_str(), args.data(),
|
||||
args.size(), nullptr, 0, flags);
|
||||
CXErrorCode error_code = clang_parseTranslationUnit2(
|
||||
index.cx_index, file_path.c_str(), args.data(), args.size(), nullptr, 0, flags, &cx_tu);
|
||||
assert(!error_code);
|
||||
}
|
||||
|
||||
TranslationUnit::~TranslationUnit() {
|
||||
|
157
query_db.cc
157
query_db.cc
@ -3,10 +3,11 @@
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "cxxopts.hpp"
|
||||
#include "optional.h"
|
||||
#include "compilation_database_loader.h"
|
||||
|
||||
using FileId = uint64_t;
|
||||
//#include "cxxopts.hpp"
|
||||
#include "optional.h"
|
||||
#include "indexer.h"
|
||||
|
||||
struct FileDatabase {
|
||||
std::unordered_map<std::string, FileId> filename_to_file_id;
|
||||
@ -30,10 +31,6 @@ struct File {
|
||||
std::vector<SymbolIdx> defined_symbols;
|
||||
};
|
||||
|
||||
struct TypeDef {};
|
||||
struct FuncDef {};
|
||||
struct VarDef {};
|
||||
|
||||
struct QueryableEntry {
|
||||
const char* const str;
|
||||
};
|
||||
@ -169,36 +166,87 @@ std::istream& operator >> (std::istream& is, Command& obj) {
|
||||
// TODO: allow user to decide some indexer choices, ie, do we define
|
||||
// TODO: may want to run indexer in separate process to avoid indexer/compiler crashes?
|
||||
|
||||
std::unordered_map<std::string, std::string> ParseOptions(int argc, char** argv) {
|
||||
std::unordered_map<std::string, std::string> output;
|
||||
|
||||
std::string previous_arg;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string arg = argv[i];
|
||||
|
||||
if (arg[0] != '-') {
|
||||
if (previous_arg.size() == 0) {
|
||||
std::cerr << "Invalid arguments; switches must start with -" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
output[previous_arg] = arg;
|
||||
previous_arg = "";
|
||||
}
|
||||
else {
|
||||
output[arg] = "";
|
||||
previous_arg = arg;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
bool HasOption(const std::unordered_map<std::string, std::string>& options, const std::string& option) {
|
||||
return options.find(option) != options.end();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// cxxopts throws exceptions... replace/rewrite lib?
|
||||
try {
|
||||
cxxopts::Options options("indexer", "C++ indexer powered by libclang");
|
||||
std::unordered_map<std::string, std::string> options = ParseOptions(argc, argv);
|
||||
|
||||
options.add_options()
|
||||
("h,help", "Print help (this output)")
|
||||
("list-commands", "Print information about the query commands")
|
||||
("p,project", "Path to compile_commands.json. Needed for the server, and optionally by clients if there are multiple servers running.")
|
||||
;
|
||||
if (argc == 1 || options.find("--help") != options.end()) {
|
||||
std::cout << R"help(clang-indexer help:
|
||||
|
||||
// Server options.
|
||||
options.add_options("server")
|
||||
("server", "Flag indicating that the indexer should create an index that can be queried against using separate invocations of this binary (using the --command flag).", cxxopts::value<bool>())
|
||||
("cache-dir", "Path to cache index. Database cache will be restored if present. If not present, the index will be in-memory only.")
|
||||
("threads", "Number of threads to use for indexing and querying tasks.")
|
||||
;
|
||||
General:
|
||||
--help Print this help information.
|
||||
--help-commands
|
||||
Print all available query commands.
|
||||
--project Path to compile_commands.json. Needed for the server, and
|
||||
optionally by clients if there are multiple servers running.
|
||||
--print-config
|
||||
Emit all configuration data this executable is using.
|
||||
|
||||
|
||||
// Client options.
|
||||
options.add_options("client")
|
||||
("c,command", "Execute a query command against the index. See --command-help. Presence of this flag indicates that the indexer is in client mode.", cxxopts::value<Command>())
|
||||
("f,file", "File name to run the index query on", cxxopts::value<std::string>())
|
||||
("l,location", "A symbol location in the active file the query will operate on. Format is line:column, ie, 10:5, for line 10, column 5.", cxxopts::value<std::string>())
|
||||
("preferred-symbol-location", "When looking up symbols, try to return the either the 'declaration' or the 'definition'. Defaults to 'definition'.", cxxopts::value<PreferredSymbolLocation>())
|
||||
;
|
||||
Server:
|
||||
--server If present, this binary will run in server mode. The binary
|
||||
will not return until killed or an exit is requested. The
|
||||
server computes and caches an index of the entire program
|
||||
which is then queried by short-lived client processes. A
|
||||
client is created by running this binary with a --command
|
||||
flag.
|
||||
--cache-dir Directory to cache the index and other useful information. If
|
||||
a previous cache is present, the database will try to reuse
|
||||
it. If this flag is not present, the database will be
|
||||
in-memory only.
|
||||
--threads Number of threads to use for indexing and querying tasks.
|
||||
This value is optional; a good estimate is computed by
|
||||
default.
|
||||
|
||||
options.parse(argc, argv);
|
||||
|
||||
Client:
|
||||
--command Execute a query command against the index. See
|
||||
--command-help for a listing of valid commands and a
|
||||
description of what they do. Presence of this flag indicates
|
||||
that the indexer is in client mode; this flag is mutually
|
||||
exclusive with --server.
|
||||
--location Location of the query. Some commands require only a file,
|
||||
other require a line and column as well. Format is
|
||||
filename[:line:column]. For example, "foobar.cc" and
|
||||
"foobar.cc:1:10" are valid inputs.
|
||||
--preferred-symbol-location
|
||||
When looking up symbols, try to return either the
|
||||
'declaration' or the 'definition'. Defaults to 'definition'.
|
||||
)help";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (options.count("list-commands")) {
|
||||
std::cout << R"(Available commands:
|
||||
if (HasOption(options, "--help-commands")) {
|
||||
std::cout << R"(Available commands:
|
||||
|
||||
callees:
|
||||
callers:
|
||||
@ -228,39 +276,28 @@ int main(int argc, char** argv) {
|
||||
search:
|
||||
Search for a symbol by name.
|
||||
)";
|
||||
exit(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (HasOption(options, "--project")) {
|
||||
std::vector<CompilationEntry> entries = LoadCompilationEntriesFromDirectory(options["--project"]);
|
||||
|
||||
|
||||
std::vector<ParsingDatabase> dbs;
|
||||
for (const CompilationEntry& entry : entries) {
|
||||
std::cout << "Parsing " << entry.filename << std::endl;
|
||||
ParsingDatabase db = Parse(entry.filename, entry.args);
|
||||
|
||||
dbs.emplace_back(db);
|
||||
std::cout << db.ToString() << std::endl << std::endl;
|
||||
}
|
||||
|
||||
if (argc == 1 || options.count("help")) {
|
||||
std::cout << options.help({ "", "server", "client" }) << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
catch (cxxopts::OptionException exc) {
|
||||
fail(exc.what());
|
||||
std::cin.get();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
std::string command;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "--command") == 0) {
|
||||
if ((i + 1) >= argc)
|
||||
fail("missing --command type");
|
||||
|
||||
command = argv[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (command == "")
|
||||
fail("missing --command switch");
|
||||
|
||||
|
||||
|
||||
if (command == "query") {
|
||||
|
||||
}
|
||||
|
||||
std::cout << "Running command " << command;
|
||||
*/
|
||||
std::cout << "Invalid arguments. Try --help.";
|
||||
exit(1);
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user