Skip to content

Commit

Permalink
All crossreference database implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
mjessome committed Jan 13, 2014
1 parent f803538 commit 1044f3f
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ set(LLVM_LINK_COMPONENTS
support
mc
)
set(LLVM_LDFLAGS
"${LLVM_LDFLAGS} -lsqlite3"
)

ADD_DEFINITIONS("-std=c++11")
set(CMAKE_CXX_FLAGS
Expand All @@ -14,6 +17,7 @@ set(CMAKE_CXX_FLAGS
add_clang_executable(clang-scope
ClangScope.cpp
Indexer.cpp
CrossReference.cpp
)

target_link_libraries(clang-scope
Expand Down
19 changes: 19 additions & 0 deletions ClangScope.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
#pragma once
#include <assert.h>

#define LOG(level, msg) if (LogLevel >= level) std::cout << msg;

enum ReferenceType {
Declaration = 0,
Definition,
Override,
Use,
ReferenceType_Max
};

enum IdentifierType {
Enum = 0,
Function,
Namespace,
Type,
Typedef,
Variable,
IdentifierType_Max
};
153 changes: 153 additions & 0 deletions CrossReference.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#include <iostream>

#include "ClangScope.h"
#include "CrossReference.h"

static const std::string SQLCreateDB(
"CREATE TABLE IF NOT EXISTS files( "
" id INTEGER, "
" name TEXT, "
" cmd_line TEXT, " // Command used to build this file,
// from the compilationdb.
" PRIMARY KEY (id) );"
// Declarations holds a single top-level declaration for each qualified name
"CREATE TABLE IF NOT EXISTS declarations( "
" id INTEGER, "
" name TEXT, " // Qualified name.
" usr TEXT," // This declaration's USR.
" type INTEGER, " // IdentifierType.
" PRIMARY KEY (id) );"
// References holds all references that refer to a declaration.
// In the case of a use, file:line:col corresponds to the usage location.
"CREATE TABLE IF NOT EXISTS _references( "
" id INTEGER, "
" declaration INTEGER, " // References declarations(id).
" reftype INTEGER, " // Type of reference.
// 0 - Declaration
// 1 - Definition
// 2 - Override
// 3 - Use
" file INTEGER, " // References files(id).
" line INTEGER, "
" col INTEGER, "
" txt TEXT, "
" PRIMARY KEY (id), "
" UNIQUE (declaration,file,line,col) " // No duplicated references.
" ON CONFLICT IGNORE );");

bool CrossReference::PrepareStatement(std::string Stmt, sqlite3_stmt **ppstmt) {
const char *end = 0;
int rc = sqlite3_prepare(Db, Stmt.c_str(), Stmt.size(), ppstmt, &end);
if (rc != SQLITE_OK) {
std::cerr << "ERROR ON PREPARE: " << rc << std::endl;
std::cerr << Stmt << std::endl;
}
return (rc == SQLITE_OK);
}

bool CrossReference::PrepareInsertStatements() {
int rc = 0;
rc |= PrepareStatement("INSERT INTO declarations VALUES (NULL, ?, ?);",
&InsDecl);
rc |= PrepareStatement(
"INSERT INTO _references VALUES (NULL, ?, ?, ?, ?, ?, ?);", &InsRef);
rc |= PrepareStatement("INSERT INTO files VALUES (NULL, ?, ?);", &InsFile);
return rc;
}

bool CrossReference::PrepareQueryStatements() {
int rc = 0;
// A query by ReferenceType / name
rc |= PrepareStatement("SELECT name,line,col,txt FROM files "
"JOIN ("
" SELECT file,line,col,txt FROM _references "
" WHERE ( reftype=? AND declaration IN ("
" SELECT id "
" FROM declarations WHERE ( name=? "
" AND type=? ) LIMIT 1 ) ) ) "
"ON file = id;",
&GetByRefType);
return rc;
}

bool CrossReference::OpenDb(std::string FileName, bool create) {
int flags = SQLITE_OPEN_READWRITE;
if (create)
flags |= SQLITE_OPEN_CREATE;
int rc = sqlite3_open_v2(FileName.c_str(), &Db, flags, NULL);
if (rc != SQLITE_OK) {
std::cerr << sqlite3_errmsg(Db);
sqlite3_close(Db);
return false;
}

CreateTables();

// TODO: These should be on a config switch
PrepareInsertStatements();
PrepareQueryStatements();

Exec("PRAGMA temp_store = 2;" // Store temporary data in memory
"PRAGMA journal_mode = MEMORY;" // Journal in memory
"PRAGMA synchronous = OFF;" // Don't wait for disk to sync on file write
);
this->FileName = FileName;
return true;
}

void CrossReference::CloseDb() {
EndTransaction();
sqlite3_close(Db);
}

bool CrossReference::Exec(std::string ExecStr) {
char *err = 0;
int rc = sqlite3_exec(Db, ExecStr.c_str(), 0, 0, &err);
if (rc != SQLITE_OK) {
std::cerr << err;
sqlite3_free(err);
}
return rc == SQLITE_OK;
}

unsigned CrossReference::StepAndReset(sqlite3_stmt *ppstmt) {
int rc = sqlite3_step(ppstmt);
if (rc != SQLITE_DONE) {
std::cerr << "ERROR on STEP: " << rc << std::endl;
return 0;
}
sqlite3_reset(ppstmt);
return sqlite3_last_insert_rowid(Db);
}

bool CrossReference::CreateTables() { return Exec(SQLCreateDB); }

unsigned
CrossReference::InsertDeclaration(std::string Name, std::string USR,
IdentifierType IdType) {
int rc = 0;
rc |= sqlite3_bind_text(InsDecl, 1, Name.c_str(), Name.length(), 0);
rc |= sqlite3_bind_int(InsDecl, 2, IdType);
if (rc != SQLITE_OK) return 0;
return (rc != SQLITE_OK) ? 0 : StepAndReset(InsDecl);
}

unsigned CrossReference::InsertReference(unsigned Decl, ReferenceType RefType,
unsigned File, unsigned Line,
unsigned Col, std::string Text) {
int rc = 0;
rc |= sqlite3_bind_int(InsRef, 1, Decl);
rc |= sqlite3_bind_int(InsRef, 2, RefType);
rc |= sqlite3_bind_int(InsRef, 3, File);
rc |= sqlite3_bind_int(InsRef, 4, Line);
rc |= sqlite3_bind_int(InsRef, 5, Col);
rc |= sqlite3_bind_text(InsRef, 6, Text.c_str(), Text.length(), 0);
return (rc != SQLITE_OK) ? 0 : StepAndReset(InsRef);
}

unsigned CrossReference::InsertFile(std::string File, std::string CmdLine) {
int rc = 0;
rc |= sqlite3_bind_text(InsFile, 1, File.c_str(), File.length(), 0);
rc |= sqlite3_bind_text(InsFile, 2, CmdLine.c_str(), CmdLine.length(), 0);
return (rc != SQLITE_OK) ? 0 : StepAndReset(InsFile);
}
53 changes: 52 additions & 1 deletion CrossReference.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,54 @@
#pragma once

class CrossReference {};
#include <sqlite3.h>
#include <string>

#include "ClangScope.h"

class CrossReference {
private:
std::string FileName;
sqlite3 *Db;
bool Transaction; // True if the database has an open transaction

bool Exec(std::string ExecStr);
unsigned StepAndReset(sqlite3_stmt *ppstmt);
bool CreateTables();

// Prepared sqlite queries
sqlite3_stmt *InsDecl;
sqlite3_stmt *InsRef;
sqlite3_stmt *InsFile;
sqlite3_stmt *GetByRefType;
bool PrepareStatement(std::string Stmt, sqlite3_stmt **ppstmt);
bool PrepareInsertStatements();
bool PrepareQueryStatements();

public:
CrossReference() : Transaction(true) {}
~CrossReference() {}

bool OpenDb(std::string FileName, bool create = true);
bool IsOpen() { return Db; }
void CloseDb();

bool BeginTransaction() {
assert(!Transaction && "Transaction already started.");
Transaction = true;
return Exec("BEGIN TRANSACTION;");
}
bool EndTransaction() {
if (!Transaction)
return true;
Transaction = false;
return Exec("END TRANSACTION;");
}

unsigned InsertDeclaration(std::string Name, std::string USR,
IdentifierType IdType);

unsigned InsertReference(unsigned Decl, ReferenceType RefType, unsigned File,
unsigned Line, unsigned Col, std::string Text);

unsigned InsertFile(std::string File, std::string CmdLine);
};

0 comments on commit 1044f3f

Please sign in to comment.