Browse Source

Initial commit

merge-requests/37/head
Jørgen Lien Sellæg 11 years ago
parent
commit
e10216f254
  1. 7
      .gitignore
  2. 7
      CMakeLists.txt
  3. 93
      README.md
  4. 82
      cmake/Modules/FindLibClang.cmake
  5. 52
      src/CMakeLists.txt
  6. 39
      src/CodeCompleteResults.cc
  7. 23
      src/CodeCompleteResults.h
  8. 16
      src/CompilationDatabase.cc
  9. 20
      src/CompilationDatabase.h
  10. 28
      src/CompileCommand.cc
  11. 16
      src/CompileCommand.h
  12. 23
      src/CompileCommands.cc
  13. 20
      src/CompileCommands.h
  14. 28
      src/CompletionString.cc
  15. 41
      src/CompletionString.h
  16. 10
      src/Cursor.cc
  17. 185
      src/Cursor.h
  18. 7
      src/Index.cc
  19. 16
      src/Index.h
  20. 59
      src/SourceLocation.cc
  21. 38
      src/SourceLocation.h
  22. 17
      src/SourceRange.cc
  23. 22
      src/SourceRange.h
  24. 33
      src/Token.cc
  25. 31
      src/Token.h
  26. 22
      src/Tokens.cc
  27. 19
      src/Tokens.h
  28. 76
      src/TranslationUnit.cc
  29. 47
      src/TranslationUnit.h
  30. 15
      src/clangmm.h
  31. 35
      tests/CMakeLists.txt
  32. 35
      tests/CodeCompleteResults_H_Test.cc
  33. 44
      tests/CompletionString_H_Test.cc
  34. 19
      tests/Cursor_H_Test.cc
  35. 2
      tests/Entry.cc
  36. 43
      tests/SourceLocation_H_Test.cc
  37. 23
      tests/Token_H_Test.cc
  38. 24
      tests/TranslationUnit_Test.cc
  39. 7
      tests/case/main.cpp

7
.gitignore vendored

@ -0,0 +1,7 @@
*
./*
!.gitignore
!*.h
!*.cc
!CMakeLists.txt

7
CMakeLists.txt

@ -0,0 +1,7 @@
cmake_minimum_required (VERSION 2.8.4)
set(project_name clangmm)
project(${project_name})
set(library_installation_path "/usr/local/lib/libclangmm/")
enable_testing()
add_subdirectory(src)
add_subdirectory(tests)

93
README.md

@ -0,0 +1,93 @@
# libclangmm - An easy to use C++-wrapper for libclang #
## About ##
This project is written by *cppit* as part of an bachelor thesis
# Install #
This section describes how to install this library on your system. The section below is tested in on unix based systems and in windows. If there are any problems please create an issue and we will look into it.
## Dependencies ##
Please install these dependencies on your system.
* libclang
* cmake
* make
* clang or gcc (compiler)
## Download the source ##
There are two ways of downloading the source
### Download the zip ###
You can download the zip [here](https://github.com/cppit/libclangmm/archive/master.zip).
### Cloning the repository ###
```
#!bash
$ git clone https://github.com/cppit/libclangmm.git
```
## Installation ##
```
#!sh
cmake .
make install
```
**Notice:** *make install* needs root privileges
# Usage #
One quick start:
```
#!c++
// lets say it is empty
std::string path("your file here");
clang::Index index(0, 0);
clang::TranslationUnit tu(&index, path);
// ReparseTranslationUnit takes a map with filepath as key
// and buffer as value
std::map<std::string, std::string> buffers;
// create buffer (this would normally be a gtk/qt-buffer or something)
std::string file;
file.append("#include <iostream>");
file.append("int main(int argc, char *argv[]) {\n");
file.append("std::cout << \"Hello World!\" << std::endl;\n");
file.append("return 0\n");
file.append("}");
buffers[path] = file;
// after you can use various methods to get locations
// for tokens for syntax highlighting of refactoring
// the buffer map should contain all open files. I.e in an text editor
// you could have more than one file open at the same time. Putting the
// files in this std::map will make the translationunit be reparsed
// from memory instead of from file.
tu.ReparseTranslationUnit(path, buffers);
// zero is the start of the buffer
clang::SourceLocation start(&tu, path, 0);
// the 129 value is arbitrary, you must set it to the size of your
// buffer (the number of chars in the buffer)
clang::SourceLocation end(&tu, path, 129);
clang::SourceRange range(&start, &end);
clang::Tokens tokens(&tu, &range);
// now tokens are stored in "tokens" we can extract ranges that are
// comments for instance
std::vector<clang::SourceRange> ranges;
for (auto &t : tokens.tokens()) {
if (t.kind() == clang::Token_Comment) {
ranges.emplace_back(&tu, &t);
}
}
```
For more examples see tests/

82
cmake/Modules/FindLibClang.cmake

@ -0,0 +1,82 @@
#
# Try to find libclang
#
# Once done this will define:
# - LIBCLANG_FOUND
# System has libclang.
# - LIBCLANG_INCLUDE_DIRS
# The libclang include directories.
# - LIBCLANG_LIBRARIES
# The libraries needed to use libclang.
# - LIBCLANG_LIBRARY_DIR
# The path to the directory containing libclang.
# - LIBCLANG_KNOWN_LLVM_VERSIONS
# Known LLVM release numbers.
# most recent versions come first
set(LIBCLANG_KNOWN_LLVM_VERSIONS 3.6
3.5.1
3.5.0 #Arch Linux
3.5 #LLVM Debian/Ubuntu packages from http://llvm.org/apt/
3.4.2 3.4.1 3.4 3.3 3.2 3.1)
set(libclang_llvm_header_search_paths)
set(libclang_llvm_lib_search_paths
# LLVM Fedora
/usr/lib/llvm
)
foreach (version ${LIBCLANG_KNOWN_LLVM_VERSIONS})
list(APPEND libclang_llvm_header_search_paths
# LLVM Debian/Ubuntu nightly packages: http://llvm.org/apt/
"/usr/lib/llvm-${version}/include"
# LLVM MacPorts
"/opt/local/libexec/llvm-${version}/include"
# LLVM Homebrew
"/usr/local/Cellar/llvm/${version}/include"
# LLVM Homebrew/versions
"/usr/local/lib/llvm-${version}/include"
)
list(APPEND libclang_llvm_lib_search_paths
# LLVM Debian/Ubuntu nightly packages: http://llvm.org/apt/
"/usr/lib/llvm-${version}/lib/"
# LLVM MacPorts
"/opt/local/libexec/llvm-${version}/lib"
# LLVM Homebrew
"/usr/local/Cellar/llvm/${version}/lib"
# LLVM Homebrew/versions
"/usr/local/lib/llvm-${version}/lib"
)
endforeach()
find_path(LIBCLANG_INCLUDE_DIR clang-c/Index.h
PATHS ${libclang_llvm_header_search_paths}
PATH_SUFFIXES LLVM/include #Windows package from http://llvm.org/releases/
DOC "The path to the directory that contains clang-c/Index.h")
# On Windows with MSVC, the import library uses the ".imp" file extension
# instead of the comon ".lib"
if (MSVC)
find_file(LIBCLANG_LIBRARY libclang.imp
PATH_SUFFIXES LLVM/lib
DOC "The file that corresponds to the libclang library.")
endif()
find_library(LIBCLANG_LIBRARY NAMES libclang.imp libclang clang
PATHS ${libclang_llvm_lib_search_paths}
PATH_SUFFIXES LLVM/lib #Windows package from http://llvm.org/releases/
DOC "The file that corresponds to the libclang library.")
get_filename_component(LIBCLANG_LIBRARY_DIR ${LIBCLANG_LIBRARY} PATH)
set(LIBCLANG_LIBRARIES ${LIBCLANG_LIBRARY})
set(LIBCLANG_INCLUDE_DIRS ${LIBCLANG_INCLUDE_DIR})
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBCLANG_FOUND to TRUE if
# all listed variables are TRUE
find_package_handle_standard_args(LibClang DEFAULT_MSG
LIBCLANG_LIBRARY LIBCLANG_INCLUDE_DIR)
mark_as_advanced(LIBCLANG_INCLUDE_DIR LIBCLANG_LIBRARY)

52
src/CMakeLists.txt

@ -0,0 +1,52 @@
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_HOME_DIRECTORY}/cmake/Modules/")
message("Searcing for libclang")
#LIBCLANG_FOUND System has libclang.
#LIBCLANG_INCLUDE_DIRS The libclang include directories.
#LIBCLANG_LIBRARIES The libraries needed to use libclang.
#LIBCLANG_LIBRARY_DIR The path to the directory containing libclang.
#LIBCLANG_KNOWN_LLVM_VERSIONS Known LLVM release numbers.
find_package(LibClang REQUIRED)
set(header_files
clangmm.h
CodeCompleteResults.h
CompilationDatabase.h
CompileCommand.h
CompileCommands.h
CompletionString.h
Cursor.h
Index.h
SourceLocation.h
SourceRange.h
Token.h
Tokens.h
TranslationUnit.h
)
set(cc_files
CodeCompleteResults.cc
CompilationDatabase.cc
CompileCommand.cc
CompileCommands.cc
CompletionString.cc
Cursor.cc
Index.cc
SourceLocation.cc
SourceRange.cc
Token.cc
Tokens.cc
TranslationUnit.cc
)
add_library(${project_name} SHARED ${header_files} ${cc_files})
include_directories(${LIBCLANG_INCLUDE_DIRS})
target_link_libraries(${project_name} ${LIBCLANG_LIBRARIES})
install(TARGETS ${project_name}
LIBRARY DESTINATION ${library_installation_path})
install(FILES ${header_files}
DESTINATION ${library_installation_path}/include)

39
src/CodeCompleteResults.cc

@ -0,0 +1,39 @@
#include "CodeCompleteResults.h"
#include "CompletionString.h"
clang::CodeCompleteResults::
CodeCompleteResults(clang::TranslationUnit *tu,
const std::string &file_name,
const std::map<std::string, std::string> &buffers,
int line_num,
int column) {
std::vector<CXUnsavedFile> files;
for (auto &buffer : buffers) {
CXUnsavedFile file;
file.Filename = buffer.first.c_str();
file.Contents = buffer.second.c_str();
file.Length = buffer.second.size();
files.push_back(file);
}
results_ = clang_codeCompleteAt(tu->tu_,
file_name.c_str(),
line_num,
column,
files.data(),
files.size(),
clang_defaultCodeCompleteOptions());
clang_sortCodeCompletionResults(results_->Results, results_->NumResults);
}
int clang::CodeCompleteResults::
size() {
return results_->NumResults;
}
clang::CompletionString clang::CodeCompleteResults::
get(int i) {
if (i > size()) {
// TODO(zalox) return type
}
return CompletionString(results_->Results[i].CompletionString);
}

23
src/CodeCompleteResults.h

@ -0,0 +1,23 @@
#ifndef CODECOMPLETERESULTS_H_
#define CODECOMPLETERESULTS_H_
#include <clang-c/Index.h>
#include "TranslationUnit.h"
namespace clang {
class CompletionString;
class CodeCompleteResults {
public:
CodeCompleteResults(TranslationUnit *tu,
const std::string &file_name,
const std::map<std::string, std::string> &buffers,
int line_num,
int column);
CompletionString get(int index);
int size();
private:
CXCodeCompleteResults *results_;
};
} // namespace clang
#endif // CODECOMPLETERESULTS_H_

16
src/CompilationDatabase.cc

@ -0,0 +1,16 @@
#include "CompilationDatabase.h"
#include <iostream>
clang::CompilationDatabase::
CompilationDatabase(const std::string &project_path) {
CXCompilationDatabase_Error error;
db_ = clang_CompilationDatabase_fromDirectory(project_path.c_str(), &error);
if(error) {
// TODO(user) error code...
}
}
clang::CompilationDatabase::
~CompilationDatabase() {
clang_CompilationDatabase_dispose(db_);
}

20
src/CompilationDatabase.h

@ -0,0 +1,20 @@
#ifndef COMPILATIONDATABASE_H_
#define COMPILATIONDATABASE_H_
#include <clang-c/CXCompilationDatabase.h>
#include <clang-c/Index.h>
#include <string>
namespace clang {
class CompileCommands;
class CompilationDatabase {
public:
explicit CompilationDatabase(const std::string &project_path);
CompilationDatabase();
~CompilationDatabase();
private:
CXCompilationDatabase db_;
friend CompileCommands;
};
}
#endif // COMPILATIONDATABASE_H_

28
src/CompileCommand.cc

@ -0,0 +1,28 @@
#include "CompileCommand.h"
#include "CompileCommands.h"
#include <iostream>
clang::CompileCommand::
CompileCommand(int nth, clang::CompileCommands *commands) {
command_ = clang_CompileCommands_getCommand(commands->commands_, nth);
}
std::string clang::CompileCommand::
get_command() {
std::string res;
unsigned N = clang_CompileCommand_getNumArgs(command_);
for (int i = 0; i < N; i++) {
res += clang_getCString(clang_CompileCommand_getArg(command_, i));
}
return res;
}
std::vector<std::string> clang::CompileCommand::
get_command_as_args() {
unsigned N = clang_CompileCommand_getNumArgs(command_);
std::vector<std::string> res(N);
for (int i = 0; i < N; i++) {
res[i] = clang_getCString(clang_CompileCommand_getArg(command_, i));
}
return res;
}

16
src/CompileCommand.h

@ -0,0 +1,16 @@
#ifndef COMPILECOMMAND_H_
#define COMPILECOMMAND_H_
#include "CompilationDatabase.h"
#include <vector>
namespace clang {
class CompileCommand {
public:
CompileCommand(int nth, CompileCommands *commands);
std::string get_command();
std::vector<std::string> get_command_as_args();
private:
CXCompileCommand command_;
};
}
#endif // COMPILECOMMAND_H_

23
src/CompileCommands.cc

@ -0,0 +1,23 @@
#include "CompileCommands.h"
#include <iostream>
clang::CompileCommands::
CompileCommands(const std::string &filename, CompilationDatabase *db) {
commands_ =
clang_CompilationDatabase_getCompileCommands(db->db_, filename.c_str());
}
clang::CompileCommands::
~CompileCommands() {
clang_CompileCommands_dispose(commands_);
}
std::vector<clang::CompileCommand> clang::CompileCommands::
get_commands() {
unsigned N = clang_CompileCommands_getSize(commands_);
std::vector<clang::CompileCommand> res;
for (auto i = 0; i < N; i++) {
res.emplace_back(clang::CompileCommand(i, this));
}
return res;
}

20
src/CompileCommands.h

@ -0,0 +1,20 @@
#ifndef COMPILECOMMANDS_H_
#define COMPILECOMMANDS_H_
#include "CompilationDatabase.h"
#include "CompileCommand.h"
#include <clang-c/CXCompilationDatabase.h>
#include <string>
#include <vector>
namespace clang {
class CompileCommands {
public:
CompileCommands(const std::string &filename, CompilationDatabase *db);
std::vector<CompileCommand> get_commands();
~CompileCommands();
private:
CXCompileCommands commands_;
friend class CompileCommand;
};
}
#endif // COMPILECOMMANDS_H_

28
src/CompletionString.cc

@ -0,0 +1,28 @@
#include "CompletionString.h"
clang::CompletionString::
CompletionString(const CXCompletionString &str) {
str_ = str;
}
int clang::CompletionString::
get_num_chunks() {
return clang_getNumCompletionChunks(str_);
}
std::vector<clang::CompletionChunk> clang::CompletionString::
get_chunks() {
std::vector<clang::CompletionChunk> res;
if (clang_getCompletionAvailability(str_) == CXAvailability_Available) {
for (auto i = 0; i < get_num_chunks(); i++) {
res.emplace_back(clang_getCString(clang_getCompletionChunkText(str_, i)),
static_cast<CompletionChunkKind>
(clang_getCompletionChunkKind(str_, i)));
}
}
return res;
}
clang::CompletionChunk::
CompletionChunk(std::string chunk, clang::CompletionChunkKind kind) :
chunk_(chunk), kind_(kind) { }

41
src/CompletionString.h

@ -0,0 +1,41 @@
#ifndef COMPLETIONSTRING_H_
#define COMPLETIONSTRING_H_
#include <clang-c/Index.h>
#include "CodeCompleteResults.h"
namespace clang {
enum CompletionChunkKind {
CompletionChunk_Optional, CompletionChunk_TypedText,
CompletionChunk_Text, CompletionChunk_Placeholder,
CompletionChunk_Informative, CompletionChunk_CurrentParameter,
CompletionChunk_LeftParen, CompletionChunk_RightParen,
CompletionChunk_LeftBracket, CompletionChunk_RightBracket,
CompletionChunk_LeftBrace, CompletionChunk_RightBrace,
CompletionChunk_LeftAngle, CompletionChunk_RightAngle,
CompletionChunk_Comma, CompletionChunk_ResultType,
CompletionChunk_Colon, CompletionChunk_SemiColon,
CompletionChunk_Equal, CompletionChunk_HorizontalSpace,
CompletionChunk_VerticalSpace
};
class CompletionChunk {
public:
CompletionChunk(std::string chunk, CompletionChunkKind kind);
const std::string& chunk() const { return chunk_; }
const CompletionChunkKind& kind() const { return kind_; }
private:
std::string chunk_;
CompletionChunkKind kind_;
};
class CompletionString {
public:
std::vector<CompletionChunk> get_chunks();
int get_num_chunks();
private:
explicit CompletionString(const CXCompletionString &str);
CXCompletionString str_;
friend CodeCompleteResults;
};
} // namespace clang
#endif // COMPLETIONSTRING_H_

10
src/Cursor.cc

@ -0,0 +1,10 @@
#include "Cursor.h"
const clang::CursorKind clang::Cursor::kind() {
return (CursorKind) clang_getCursorKind(this->cursor_);
}
clang::Cursor::
Cursor(clang::TranslationUnit *tu, clang::SourceLocation *source_location) {
cursor_ = clang_getCursor(tu->tu_, source_location->location_);
}

185
src/Cursor.h

@ -0,0 +1,185 @@
#ifndef CURSOR_H_
#define CURSOR_H_
#include "TranslationUnit.h"
#include "SourceLocation.h"
namespace clang {
enum class CursorKind {
UnexposedDecl = 1,
StructDecl = 2,
UnionDecl = 3,
ClassDecl = 4,
EnumDecl = 5,
FieldDecl = 6,
EnumConstantDecl = 7,
FunctionDecl = 8,
VarDecl = 9,
ParmDecl = 10,
ObjCInterfaceDecl = 11,
ObjCCategoryDecl = 12,
ObjCProtocolDecl = 13,
ObjCPropertyDecl = 14,
ObjCIvarDecl = 15,
ObjCInstanceMethodDecl = 16,
ObjCClassMethodDecl = 17,
ObjCImplementationDecl = 18,
ObjCCategoryImplDecl = 19,
TypedefDecl = 20,
CXXMethod = 21,
Namespace = 22,
LinkageSpec = 23,
Constructor = 24,
Destructor = 25,
ConversionFunction = 26,
TemplateTypeParameter = 27,
NonTypeTemplateParameter = 28,
TemplateTemplateParameter = 29,
FunctionTemplate = 30,
ClassTemplate = 31,
ClassTemplatePartialSpecialization = 32,
NamespaceAlias = 33,
UsingDirective = 34,
UsingDeclaration = 35,
TypeAliasDecl = 36,
ObjCSynthesizeDecl = 37,
ObjCDynamicDecl = 38,
CXXAccessSpecifier = 39,
FirstDecl = UnexposedDecl,
LastDecl = CXXAccessSpecifier,
FirstRef = 40,
ObjCSuperClassRef = 40,
ObjCProtocolRef = 41,
ObjCClassRef = 42,
TypeRef = 43,
CXXBaseSpecifier = 44,
TemplateRef = 45,
NamespaceRef = 46,
MemberRef = 47,
LabelRef = 48,
OverloadedDeclRef = 49,
VariableRef = 50,
LastRef = VariableRef,
FirstInvalid = 70,
InvalidFile = 70,
NoDeclFound = 71,
NotImplemented = 72,
InvalidCode = 73,
LastInvalid = InvalidCode,
FirstExpr = 100,
UnexposedExpr = 100,
DeclRefExpr = 101,
MemberRefExpr = 102,
CallExpr = 103,
ObjCMessageExpr = 104,
BlockExpr = 105,
IntegerLiteral = 106,
FloatingLiteral = 107,
ImaginaryLiteral = 108,
StringLiteral = 109,
CharacterLiteral = 110,
ParenExpr = 111,
UnaryOperator = 112,
ArraySubscriptExpr = 113,
BinaryOperator = 114,
CompoundAssignOperator = 115,
ConditionalOperator = 116,
CStyleCastExpr = 117,
CompoundLiteralExpr = 118,
InitListExpr = 119,
AddrLabelExpr = 120,
StmtExpr = 121,
GenericSelectionExpr = 122,
GNUNullExpr = 123,
CXXStaticCastExpr = 124,
CXXDynamicCastExpr = 125,
CXXReinterpretCastExpr = 126,
CXXConstCastExpr = 127,
CXXFunctionalCastExpr = 128,
CXXTypeidExpr = 129,
CXXBoolLiteralExpr = 130,
CXXNullPtrLiteralExpr = 131,
CXXThisExpr = 132,
CXXThrowExpr = 133,
CXXNewExpr = 134,
CXXDeleteExpr = 135,
UnaryExpr = 136,
ObjCStringLiteral = 137,
ObjCEncodeExpr = 138,
ObjCSelectorExpr = 139,
ObjCProtocolExpr = 140,
ObjCBridgedCastExpr = 141,
PackExpansionExpr = 142,
SizeOfPackExpr = 143,
LambdaExpr = 144,
ObjCBoolLiteralExpr = 145,
ObjCSelfExpr = 146,
LastExpr = ObjCSelfExpr,
FirstStmt = 200,
UnexposedStmt = 200,
LabelStmt = 201,
CompoundStmt = 202,
CaseStmt = 203,
DefaultStmt = 204,
IfStmt = 205,
SwitchStmt = 206,
WhileStmt = 207,
DoStmt = 208,
ForStmt = 209,
GotoStmt = 210,
IndirectGotoStmt = 211,
ContinueStmt = 212,
BreakStmt = 213,
ReturnStmt = 214,
GCCAsmStmt = 215,
AsmStmt = GCCAsmStmt,
ObjCAtTryStmt = 216,
ObjCAtCatchStmt = 217,
ObjCAtFinallyStmt = 218,
ObjCAtThrowStmt = 219,
ObjCAtSynchronizedStmt = 220,
ObjCAutoreleasePoolStmt = 221,
ObjCForCollectionStmt = 222,
CXXCatchStmt = 223,
CXXTryStmt = 224,
CXXForRangeStmt = 225,
SEHTryStmt = 226,
SEHExceptStmt = 227,
SEHFinallyStmt = 228,
MSAsmStmt = 229,
NullStmt = 230,
DeclStmt = 231,
LastStmt = DeclStmt,
TranslationUnit = 300,
FirstAttr = 400,
UnexposedAttr = 400,
IBActionAttr = 401,
IBOutletAttr = 402,
IBOutletCollectionAttr = 403,
CXXFinalAttr = 404,
CXXOverrideAttr = 405,
AnnotateAttr = 406,
AsmLabelAttr = 407,
LastAttr = AsmLabelAttr,
PreprocessingDirective = 500,
MacroDefinition = 501,
MacroExpansion = 502,
MacroInstantiation = MacroExpansion,
InclusionDirective = 503,
FirstPreprocessing = PreprocessingDirective,
LastPreprocessing = InclusionDirective,
ModuleImportDecl = 600,
FirstExtraDecl = ModuleImportDecl,
LastExtraDecl = ModuleImportDecl,
};
class Cursor {
public:
Cursor(TranslationUnit *tu, SourceLocation *source_location);
const CursorKind kind();
private:
CXCursor cursor_;
friend SourceRange;
friend SourceLocation;
};
} // namespace clang
#endif // CURSOR_H_

7
src/Index.cc

@ -0,0 +1,7 @@
#include "Index.h"
clang::Index::
Index(int excludeDeclarationsFromPCH, int displayDiagnostics) {
index_ = clang_createIndex(excludeDeclarationsFromPCH,
displayDiagnostics);
}

16
src/Index.h

@ -0,0 +1,16 @@
#ifndef INDEX_H_
#define INDEX_H_
#include <clang-c/Index.h>
namespace clang {
class TranslationUnit;
class Index {
public:
Index(int excludeDeclarationsFromPCH, int displayDiagnostics);
private:
CXIndex index_;
friend TranslationUnit;
};
} // namespace clang
#endif // INDEX_H_

59
src/SourceLocation.cc

@ -0,0 +1,59 @@
#include "SourceLocation.h"
// // // // // // // //
// SourceLocation //
// // // // // // // //
clang::SourceLocation::
SourceLocation(clang::TranslationUnit *tu,
const std::string &filename,
int line_number,
int line_offset) {
CXFile file = clang_getFile(tu->tu_,
filename.c_str());
location_ = clang_getLocation(tu->tu_,
file,
line_number,
line_offset);
}
clang::SourceLocation::
SourceLocation(Cursor *cursor) {
location_ = clang_getCursorLocation(cursor->cursor_);
}
clang::SourceLocation::
SourceLocation(clang::SourceRange *range, bool start) {
location_ = start ? clang_getRangeStart(range->range_) :
clang_getRangeEnd(range->range_);
}
clang::SourceLocation::
SourceLocation(TranslationUnit *tu,
Token *token) {
location_ = clang_getTokenLocation(tu->tu_,
token->token_);
}
clang::SourceLocation::
SourceLocation(clang::TranslationUnit *tu,
const std::string &filepath,
int offset) {
CXFile file = clang_getFile(tu->tu_,
filepath.c_str());
location_ = clang_getLocationForOffset(tu->tu_,
file,
offset);
}
void clang::SourceLocation::
get_location_info(std::string* path,
unsigned *line,
unsigned *column,
unsigned *offset) {
CXFile file;
clang_getExpansionLocation(location_, &file, line, column, offset);
if (path != NULL) {
path->operator=(((clang_getCString((clang_getFileName(file))))));
}
}

38
src/SourceLocation.h

@ -0,0 +1,38 @@
#ifndef SOURCELOCATION_H_
#define SOURCELOCATION_H_
#include "TranslationUnit.h"
#include "Token.h"
#include "Cursor.h"
namespace clang {
class SourceLocation {
public:
SourceLocation(TranslationUnit* tu,
const std::string &filename,
int line_number,
int column);
SourceLocation(TranslationUnit *tu,
Token *token);
SourceLocation(SourceRange *range, bool start);
SourceLocation(TranslationUnit *tu,
const std::string &filepath,
int offset);
explicit SourceLocation(Cursor *cursor);
void get_location_info(std::string* path,
unsigned *line,
unsigned *column,
unsigned *offset);
private:
CXSourceLocation location_;
friend SourceRange;
friend Cursor;
};
} // namespace clang
#endif // SOURCELOCATION_H_

17
src/SourceRange.cc

@ -0,0 +1,17 @@
#include "SourceRange.h"
clang::SourceRange::
SourceRange(clang::TranslationUnit *tu, clang::Token *token) {
range_ = clang_getTokenExtent(tu->tu_, token->token_);
}
clang::SourceRange::
SourceRange(clang::SourceLocation *start, clang::SourceLocation *end) {
range_ = clang_getRange(start->location_, end->location_);
}
clang::SourceRange::~SourceRange() { }
clang::SourceRange::SourceRange(Cursor *cursor) {
range_ = clang_getCursorExtent(cursor->cursor_);
}

22
src/SourceRange.h

@ -0,0 +1,22 @@
#ifndef SOURCERANGE_H_
#define SOURCERANGE_H_
#include "TranslationUnit.h"
#include "Token.h"
#include "Cursor.h"
namespace clang {
class SourceRange {
public:
SourceRange(TranslationUnit *tu, Token *token);
SourceRange(SourceLocation *start,
SourceLocation *end);
explicit SourceRange(Cursor *cursor);
~SourceRange();
private:
CXSourceRange range_;
friend Tokens;
friend SourceLocation;
};
} // namespace clang
#endif // SOURCERANGE_H_

33
src/Token.cc

@ -0,0 +1,33 @@
#include "Token.h"
#include <iostream>
// // // // //
// Token //
// // // // //
// clang::Token instansiates an token
clang::Token::Token(const CXToken &token) :
token_(token) {
}
// returns gets an source location for this token objekt
// based on the translationunit given
clang::SourceLocation clang::Token::
get_source_location(clang::TranslationUnit *tu) {
return SourceLocation(tu, this);
}
// returns a sourcerange that covers this token
clang::SourceRange clang::Token::
get_source_range(clang::TranslationUnit *tu) {
return SourceRange(tu, this);
}
// returns a string description of this tokens kind
std::string clang::Token::get_token_spelling(clang::TranslationUnit *tu) {
CXString s = clang_getTokenSpelling(tu->tu_, token_);
return std::string(clang_getCString(s));
}
const clang::TokenKind clang::Token::kind() {
return (TokenKind) clang_getTokenKind(token_);
}

31
src/Token.h

@ -0,0 +1,31 @@
#ifndef TOKEN_H_
#define TOKEN_H_
#include "SourceLocation.h"
#include "SourceRange.h"
#include "TranslationUnit.h"
namespace clang {
enum TokenKind {
Token_Punctuation,
Token_Keyword,
Token_Identifier,
Token_Literal,
Token_Comment
};
class Token {
public:
const TokenKind kind();
std::string get_token_spelling(TranslationUnit *tu);
SourceLocation get_source_location(TranslationUnit *tu);
SourceRange get_source_range(TranslationUnit *tu);
private:
explicit Token(const CXToken &token);
friend SourceRange;
friend SourceLocation;
friend Tokens;
CXToken token_;
};
} // namespace clang
#endif // TOKEN_H_

22
src/Tokens.cc

@ -0,0 +1,22 @@
#include "Tokens.h"
#include <iostream>
clang::Tokens::Tokens(clang::TranslationUnit *tu, clang::SourceRange *range) {
clang_tokenize(tu->tu_,
range->range_,
&tokens_,
&num_tokens_);
for (int i = 0; i < num_tokens_; i++) {
tks.push_back(clang::Token(tokens_[i]));
}
}
clang::Tokens::~Tokens() {
// instead of using clang_disposeTokens() the implementation
// of the latter method is just free(token_) the same as
// delete(tokens_) eliminating the need of tu*
delete tokens_;
}
std::vector<clang::Token>& clang::Tokens::tokens() {
return tks;
}

19
src/Tokens.h

@ -0,0 +1,19 @@
#ifndef TOKENS_H_
#define TOKENS_H_
#include "TranslationUnit.h"
#include "SourceRange.h"
#include "Token.h"
namespace clang {
class Tokens {
public:
Tokens(TranslationUnit *tu, SourceRange *range);
~Tokens();
std::vector<Token>& tokens();
protected:
std::vector<clang::Token> tks;
CXToken *tokens_;
unsigned num_tokens_;
};
} // namespace clang
#endif // TOKENS_H_

76
src/TranslationUnit.cc

@ -0,0 +1,76 @@
#include "TranslationUnit.h"
clang::TranslationUnit::
~TranslationUnit() {
clang_disposeTranslationUnit(tu_);
}
clang::TranslationUnit& clang::TranslationUnit::
operator=(const clang::TranslationUnit &tu) {
tu_ = tu.tu_;
return *this;
}
clang::TranslationUnit::
TranslationUnit(Index *index,
const std::string &filepath,
const std::vector<const char*> &command_line_args) {
tu_ = clang_createTranslationUnitFromSourceFile(index->index_,
filepath.c_str(),
command_line_args.size(),
command_line_args.data(),
0,
NULL);
}
clang::TranslationUnit::
TranslationUnit(Index *index,
const std::string &filepath) {
tu_ = clang_createTranslationUnitFromSourceFile(index->index_,
filepath.c_str(),
0,
NULL,
0,
NULL);
}
clang::TranslationUnit::
TranslationUnit(clang::Index *index,
const std::string &filepath,
const std::vector<const char*> &command_line_args,
const std::map<std::string, std::string> &buffers) {
std::vector<CXUnsavedFile> files;
for (auto &buffer : buffers) {
CXUnsavedFile file;
file.Filename = buffer.first.c_str();
file.Contents = buffer.second.c_str();
file.Length = buffer.second.size();
files.push_back(file);
}
tu_ =
clang_parseTranslationUnit(index->index_,
filepath.c_str(),
command_line_args.data(),
command_line_args.size(),
files.data(),
files.size(),
clang_defaultEditingTranslationUnitOptions());
}
int clang::TranslationUnit::
ReparseTranslationUnit(const std::string &file_path,
const std::map<std::string, std::string> &buffers) {
std::vector<CXUnsavedFile> files;
for (auto &buffer : buffers) {
CXUnsavedFile file;
file.Filename = buffer.first.c_str();
file.Contents = buffer.second.c_str();
file.Length = buffer.second.size();
files.push_back(file);
}
return clang_reparseTranslationUnit(tu_,
files.size(),
files.data(),
clang_defaultReparseOptions(tu_));
}

47
src/TranslationUnit.h

@ -0,0 +1,47 @@
#ifndef TRANSLATIONUNIT_H_
#define TRANSLATIONUNIT_H_
#include <clang-c/Index.h>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <iostream>
#include "Index.h"
namespace clang {
class Token;
class Tokens;
class SourceLocation;
class SourceRange;
class Cursor;
class CodeCompleteResults;
class TranslationUnit {
public:
TranslationUnit(Index *index,
const std::string &filepath,
const std::vector<const char*> &command_line_args);
TranslationUnit(Index *index,
const std::string &filepath,
const std::vector<const char*> &command_line_args,
const std::map<std::string, std::string> &buffers);
TranslationUnit(Index *index,
const std::string &filepath);
~TranslationUnit();
TranslationUnit& operator=(const TranslationUnit &tu);
int ReparseTranslationUnit(const std::string &file_path,
const std::map<std::string, std::string>
&buffers);
private:
friend Token;
friend Tokens;
friend SourceLocation;
friend SourceRange;
friend Cursor;
friend CodeCompleteResults;
CXTranslationUnit tu_;
};
} // namespace clang
#endif // TRANSLATIONUNIT_H_

15
src/clangmm.h

@ -0,0 +1,15 @@
#ifndef CLANGMM_H_
#define CLANGMM_H_
#include "TranslationUnit.h"
#include "SourceLocation.h"
#include "SourceRange.h"
#include "Token.h"
#include "Tokens.h"
#include "CompilationDatabase.h"
#include "CompileCommands.h"
#include "CompileCommand.h"
#include "CodeCompleteResults.h"
#include "CompletionString.h"
#include "Index.h"
#include "Cursor.h"
#endif // CLANGMM_H_

35
tests/CMakeLists.txt

@ -0,0 +1,35 @@
set(project_tests ${project_name}_tests)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_HOME_DIRECTORY}/cmake/Modules/")
ADD_DEFINITIONS(-DBOOST_TEST_STATIC_LINK)
message("Searcing for libclang")
#LIBCLANG_FOUND System has libclang.
#LIBCLANG_INCLUDE_DIRS The libclang include directories.
#LIBCLANG_LIBRARIES The libraries needed to use libclang.
#LIBCLANG_LIBRARY_DIR The path to the directory containing libclang.
#LIBCLANG_KNOWN_LLVM_VERSIONS Known LLVM release numbers.
find_package(LibClang REQUIRED)
find_package(Boost 1.55 COMPONENTS unit_test_framework system filesystem REQUIRED)
add_executable(${project_tests}
Entry.cc
TranslationUnit_Test.cc
CompletionString_H_Test.cc
CodeCompleteResults_H_Test.cc
Cursor_H_Test.cc
Token_H_Test.cc
SourceLocation_H_Test.cc
)
include_directories(${LIBCLANG_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} "${CMAKE_SOURCE_DIR}/src")
target_link_libraries(${project_tests} ${LIBCLANG_LIBRARIES} ${Boost_LIBRARIES} clangmm)
set(tests
${project_tests}
)
add_test(${tests} ${tests})

35
tests/CodeCompleteResults_H_Test.cc

@ -0,0 +1,35 @@
#include <boost/test/unit_test.hpp>
#include "clangmm.h"
#include <string>
BOOST_AUTO_TEST_CASE(code_complete_results) {
// [ Should be changed with mockery
std::string path("./case/main.cpp");
clang::Index index(0, 0);
clang::TranslationUnit tu(&index, path);
// ReparseTranslationUnit takes a map with filepath as key
// and buffer as value
std::map<std::string, std::string> buffers;
// create buffer
std::string file;
file.append("#include <string>\n");
file.append("int main(int argc, char *argv[]) {\n");
file.append("std::string str;\n");
file.append("str.\n");
file.append("return 0\n");
file.append("}");
buffers[path] = file;
// ]
clang::CodeCompleteResults results(&tu, path, buffers, 4, 5);
BOOST_CHECK(results.size() == 105);
BOOST_CHECK(results.get(0).get_num_chunks() == 5);
}

44
tests/CompletionString_H_Test.cc

@ -0,0 +1,44 @@
#include <boost/test/unit_test.hpp>
#include "clangmm.h"
#include <string>
BOOST_AUTO_TEST_CASE(completion_chunk) {
clang::CompletionChunk str("(", clang::CompletionChunk_LeftBrace);
BOOST_CHECK(str.chunk() == "(");
BOOST_CHECK(str.kind() == clang::CompletionChunk_LeftBrace);
}
BOOST_AUTO_TEST_CASE(completion_string) {
// [ Should be changed with mockery
std::string path("./case/main.cpp");
clang::Index index(0, 0);
clang::TranslationUnit tu(&index, path);
// ReparseTranslationUnit takes a map with filepath as key
// and buffer as value
std::map<std::string, std::string> buffers;
// create buffer
std::string file;
file.append("#include <string>\n");
file.append("int main(int argc, char *argv[]) {\n");
file.append("std::string str;\n");
file.append("str.\n");
file.append("return 0\n");
file.append("}");
buffers[path] = file;
clang::CodeCompleteResults results(&tu, path, buffers, 4, 5);
// ]
clang::CompletionString str = results.get(0);
BOOST_CHECK(str.get_num_chunks() == 5);
BOOST_CHECK(str.get_chunks().size() == 5);
}

19
tests/Cursor_H_Test.cc

@ -0,0 +1,19 @@
#include <boost/test/unit_test.hpp>
#include "clangmm.h"
#include <string>
BOOST_AUTO_TEST_CASE(cursor) {
// [ Should be changed with mockery
std::string path("./case/main.cpp");
clang::Index index(0, 0);
clang::TranslationUnit tu(&index, path);
// ]
clang::SourceLocation location(&tu, path, 6, 4);
clang::Cursor cursor(&tu, &location);
BOOST_CHECK(cursor.kind() == clang::CursorKind::ReturnStmt);
}

2
tests/Entry.cc

@ -0,0 +1,2 @@
#define BOOST_TEST_MODULE clangmm_tests
#include <boost/test/included/unit_test.hpp>

43
tests/SourceLocation_H_Test.cc

@ -0,0 +1,43 @@
#include <boost/test/unit_test.hpp>
#include "clangmm.h"
#include <string>
BOOST_AUTO_TEST_CASE(source_location) {
std::string path("./case/main.cpp");
clang::Index index(0, 0);
clang::TranslationUnit tu(&index, path);
clang::SourceLocation start(&tu, path, 0);
clang::SourceLocation end(&tu, path, 7, 1);
clang::SourceRange range(&start, &end);
clang::Tokens tokens(&tu, &range);
clang::SourceRange token_range = tokens.tokens()[28].get_source_range(&tu);
unsigned token_start_line, token_start_column, token_start_offset,
token_end_line, token_end_column, token_end_offset;
std::string token_start_path, token_end_path;
clang::SourceLocation token_start(&token_range, true);
clang::SourceLocation token_end(&token_range, false);
token_start.get_location_info(&token_start_path,
&token_start_line,
&token_start_column,
&token_start_offset);
token_end.get_location_info(&token_end_path,
&token_end_line,
&token_end_column,
&token_end_offset);
BOOST_CHECK(token_start_path == path);
BOOST_CHECK(token_start_line == 6);
BOOST_CHECK(token_start_column == 3);
BOOST_CHECK(token_start_offset == 103);
BOOST_CHECK(token_end_path == path);
BOOST_CHECK(token_end_line == 6);
BOOST_CHECK(token_end_column == 9);
BOOST_CHECK(token_end_offset == 109);
}

23
tests/Token_H_Test.cc

@ -0,0 +1,23 @@
#include <boost/test/unit_test.hpp>
#include "clangmm.h"
#include <string>
BOOST_AUTO_TEST_CASE(token) {
std::string path("./case/main.cpp");
clang::Index index(0, 0);
clang::TranslationUnit tu(&index, path);
clang::SourceLocation start(&tu, path, 0);
clang::SourceLocation end(&tu, path, 7, 1);
clang::SourceRange range(&start, &end);
clang::Tokens tokens(&tu, &range);
BOOST_CHECK(tokens.tokens().size() == 32);
BOOST_CHECK(tokens.tokens()[1].kind() == clang::TokenKind::Token_Identifier);
std::string str = tokens.tokens()[28].get_token_spelling(&tu);
BOOST_CHECK(str == "return");
}

24
tests/TranslationUnit_Test.cc

@ -0,0 +1,24 @@
#include <boost/test/unit_test.hpp>
#include "clangmm.h"
#include <string>
#include <map>
BOOST_AUTO_TEST_CASE(translation_unit) {
std::string path("./case/main.cpp");
clang::Index index(0, 0);
clang::TranslationUnit tu(&index, path);
// ReparseTranslationUnit takes a map with filepath as key
// and buffer as value
std::map<std::string, std::string> buffers;
// create buffer
std::string file = "int main(int argc, char *argv[]) {\n";
file.append("std::cout << \"Hello World!\" << std::endl;\n");
file.append("return 0\n");
file.append("}");
buffers[path] = file;
BOOST_CHECK(tu.ReparseTranslationUnit(path, buffers) == 0);
}

7
tests/case/main.cpp

@ -0,0 +1,7 @@
#include <iostream>
int main(int argc, char *argv[])
{
std::cout << "Hello, World!" << std::endl;
return 0;
}
Loading…
Cancel
Save