Browse Source

Formatted code with custom clang-format

merge-requests/37/head
eidheim 8 years ago
parent
commit
791b76b04c
  1. 9
      .clang-format
  2. 30
      README.md
  3. 18
      src/clangmm.h
  4. 26
      src/code_complete_results.cc
  5. 9
      src/code_complete_results.h
  6. 7
      src/compilation_database.h
  7. 2
      src/compile_command.cc
  8. 8
      src/compile_command.h
  9. 4
      src/compile_commands.cc
  10. 4
      src/compile_commands.h
  11. 90
      src/completion_string.cc
  12. 12
      src/completion_string.h
  13. 153
      src/cursor.cc
  14. 24
      src/cursor.h
  15. 26
      src/diagnostic.cc
  16. 17
      src/diagnostic.h
  17. 4
      src/index.h
  18. 9
      src/source_location.cc
  19. 27
      src/source_location.h
  20. 14
      src/source_range.h
  21. 20
      src/token.cc
  22. 23
      src/token.h
  23. 84
      src/tokens.cc
  24. 18
      src/tokens.h
  25. 60
      src/translation_unit.cc
  26. 33
      src/translation_unit.h
  27. 91
      src/utility.cc
  28. 8
      src/utility.h
  29. 36
      tests/code_complete_results_test.cc
  30. 48
      tests/completion_string_test.cc
  31. 20
      tests/cursor_test.cc
  32. 24
      tests/diagnostics_test.cc
  33. 12
      tests/source_location_test.cc
  34. 12
      tests/token_test.cc
  35. 10
      tests/translation_unit_test.cc

9
.clang-format

@ -0,0 +1,9 @@
IndentWidth: 2
AccessModifierOffset: -2
UseTab: Never
ColumnLimit: 0
MaxEmptyLinesToKeep: 2
SpaceBeforeParens: Never
BreakBeforeBraces: Custom
BraceWrapping: {BeforeElse: true, BeforeCatch: true}
NamespaceIndentation: All

30
README.md

@ -13,7 +13,7 @@ Developed for [juCi++](https://gitlab.com/cppit/jucipp), a lightweight, platform
## Installation ## ## Installation ##
See [installation guide](https://gitlab.com/cppit/libclangmm/blob/master/docs/install.md) See [installation guide](https://gitlab.com/cppit/libclangmm/blob/master/docs/install.md)
# Tests # ## Tests ##
To run the unit tests: To run the unit tests:
```sh ```sh
mkdir build && cd build mkdir build && cd build
@ -21,3 +21,31 @@ cmake -DBUILD_TESTING=1 ..
make make
make test make test
``` ```
## Coding style
Due to poor lambda support in clang-format, a custom clang-format is used with the following patch applied:
```diff
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index bb8efd61a3..e80a487055 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -276,6 +276,8 @@ LineState ContinuationIndenter::getInitialState(unsigned FirstIndent,
}
bool ContinuationIndenter::canBreak(const LineState &State) {
+ if(Style.ColumnLimit==0)
+ return true;
const FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *Current.Previous;
assert(&Previous == Current.Previous);
@@ -325,6 +327,8 @@ bool ContinuationIndenter::canBreak(const LineState &State) {
}
bool ContinuationIndenter::mustBreak(const LineState &State) {
+ if(Style.ColumnLimit==0)
+ return false;
const FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *Current.Previous;
if (Current.MustBreakBefore || Current.is(TT_InlineASMColon))
```

18
src/clangmm.h

@ -1,17 +1,17 @@
#ifndef CLANGMM_H_ #ifndef CLANGMM_H_
#define CLANGMM_H_ #define CLANGMM_H_
#include "translation_unit.h" #include "code_complete_results.h"
#include "source_location.h"
#include "source_range.h"
#include "token.h"
#include "tokens.h"
#include "compilation_database.h" #include "compilation_database.h"
#include "compile_commands.h"
#include "compile_command.h" #include "compile_command.h"
#include "code_complete_results.h" #include "compile_commands.h"
#include "completion_string.h" #include "completion_string.h"
#include "index.h"
#include "cursor.h" #include "cursor.h"
#include "diagnostic.h" #include "diagnostic.h"
#include "index.h"
#include "source_location.h"
#include "source_range.h"
#include "token.h"
#include "tokens.h"
#include "translation_unit.h"
#include "utility.h" #include "utility.h"
#endif // CLANGMM_H_ #endif // CLANGMM_H_

26
src/code_complete_results.cc

@ -2,22 +2,22 @@
#include "completion_string.h" #include "completion_string.h"
#include "utility.h" #include "utility.h"
clangmm::CodeCompleteResults::CodeCompleteResults(CXTranslationUnit &cx_tu, clangmm::CodeCompleteResults::CodeCompleteResults(CXTranslationUnit &cx_tu,
const std::string &buffer, const std::string &buffer,
unsigned line_num, unsigned column) { unsigned line_num, unsigned column) {
CXUnsavedFile files[1]; CXUnsavedFile files[1];
auto file_path=to_string(clang_getTranslationUnitSpelling(cx_tu)); auto file_path = to_string(clang_getTranslationUnitSpelling(cx_tu));
files[0].Filename = file_path.c_str(); files[0].Filename = file_path.c_str();
files[0].Contents = buffer.c_str(); files[0].Contents = buffer.c_str();
files[0].Length = buffer.size(); files[0].Length = buffer.size();
cx_results = clang_codeCompleteAt(cx_tu, cx_results = clang_codeCompleteAt(cx_tu,
file_path.c_str(), file_path.c_str(),
line_num, line_num,
column, column,
files, files,
1, 1,
clang_defaultCodeCompleteOptions()|CXCodeComplete_IncludeBriefComments); clang_defaultCodeCompleteOptions() | CXCodeComplete_IncludeBriefComments);
if(cx_results) if(cx_results)
clang_sortCodeCompletionResults(cx_results->Results, cx_results->NumResults); clang_sortCodeCompletionResults(cx_results->Results, cx_results->NumResults);
} }
@ -27,11 +27,11 @@ clangmm::CodeCompleteResults::CodeCompleteResults(CodeCompleteResults &&rhs) : c
} }
clangmm::CodeCompleteResults &clangmm::CodeCompleteResults::operator=(CodeCompleteResults &&rhs) { clangmm::CodeCompleteResults &clangmm::CodeCompleteResults::operator=(CodeCompleteResults &&rhs) {
if(this!=&rhs) { if(this != &rhs) {
if(cx_results) if(cx_results)
clang_disposeCodeCompleteResults(cx_results); clang_disposeCodeCompleteResults(cx_results);
cx_results=rhs.cx_results; cx_results = rhs.cx_results;
rhs.cx_results=nullptr; rhs.cx_results = nullptr;
} }
return *this; return *this;
} }

9
src/code_complete_results.h

@ -1,16 +1,17 @@
#ifndef CODECOMPLETERESULTS_H_ #ifndef CODECOMPLETERESULTS_H_
#define CODECOMPLETERESULTS_H_ #define CODECOMPLETERESULTS_H_
#include "completion_string.h"
#include <clang-c/Index.h> #include <clang-c/Index.h>
#include <map> #include <map>
#include <string> #include <string>
#include "completion_string.h"
namespace clangmm { namespace clangmm {
class CodeCompleteResults { class CodeCompleteResults {
friend class TranslationUnit; friend class TranslationUnit;
CodeCompleteResults(CXTranslationUnit &cx_tu, const std::string &buffer, CodeCompleteResults(CXTranslationUnit &cx_tu, const std::string &buffer,
unsigned line_num, unsigned column); unsigned line_num, unsigned column);
public: public:
CodeCompleteResults(CodeCompleteResults &) = delete; CodeCompleteResults(CodeCompleteResults &) = delete;
CodeCompleteResults(CodeCompleteResults &&rhs); CodeCompleteResults(CodeCompleteResults &&rhs);
@ -23,5 +24,5 @@ namespace clangmm {
CXCodeCompleteResults *cx_results; CXCodeCompleteResults *cx_results;
}; };
} // namespace clangmm } // namespace clangmm
#endif // CODECOMPLETERESULTS_H_ #endif // CODECOMPLETERESULTS_H_

7
src/compilation_database.h

@ -7,14 +7,15 @@
namespace clangmm { namespace clangmm {
class CompilationDatabase { class CompilationDatabase {
CXCompilationDatabase_Error cx_db_error; CXCompilationDatabase_Error cx_db_error;
public: public:
explicit CompilationDatabase(const std::string &project_path); explicit CompilationDatabase(const std::string &project_path);
~CompilationDatabase(); ~CompilationDatabase();
operator bool() const; operator bool() const;
CXCompilationDatabase cx_db; CXCompilationDatabase cx_db;
}; };
} } // namespace clangmm
#endif // COMPILATIONDATABASE_H_ #endif // COMPILATIONDATABASE_H_

2
src/compile_command.cc

@ -5,7 +5,7 @@
std::vector<std::string> clangmm::CompileCommand::get_arguments() { std::vector<std::string> clangmm::CompileCommand::get_arguments() {
unsigned size = clang_CompileCommand_getNumArgs(cx_command); unsigned size = clang_CompileCommand_getNumArgs(cx_command);
std::vector<std::string> arguments; std::vector<std::string> arguments;
for (unsigned i = 0; i < size; i++) for(unsigned i = 0; i < size; i++)
arguments.emplace_back(to_string(clang_CompileCommand_getArg(cx_command, i))); arguments.emplace_back(to_string(clang_CompileCommand_getArg(cx_command, i)));
return arguments; return arguments;
} }

8
src/compile_command.h

@ -1,16 +1,16 @@
#ifndef COMPILECOMMAND_H_ #ifndef COMPILECOMMAND_H_
#define COMPILECOMMAND_H_ #define COMPILECOMMAND_H_
#include <clang-c/CXCompilationDatabase.h> #include <clang-c/CXCompilationDatabase.h>
#include <vector>
#include <string> #include <string>
#include <vector>
namespace clangmm { namespace clangmm {
class CompileCommand { class CompileCommand {
public: public:
CompileCommand(const CXCompileCommand& cx_command) : cx_command(cx_command) {}; CompileCommand(const CXCompileCommand &cx_command) : cx_command(cx_command){};
std::vector<std::string> get_arguments(); std::vector<std::string> get_arguments();
CXCompileCommand cx_command; CXCompileCommand cx_command;
}; };
} } // namespace clangmm
#endif // COMPILECOMMAND_H_ #endif // COMPILECOMMAND_H_

4
src/compile_commands.cc

@ -3,7 +3,7 @@
clangmm::CompileCommands::CompileCommands(const std::string &filename, CompilationDatabase &db) { clangmm::CompileCommands::CompileCommands(const std::string &filename, CompilationDatabase &db) {
if(!filename.empty()) if(!filename.empty())
cx_commands = clang_CompilationDatabase_getCompileCommands(db.cx_db, filename.c_str()); cx_commands = clang_CompilationDatabase_getCompileCommands(db.cx_db, filename.c_str());
if(filename.empty() || clang_CompileCommands_getSize(cx_commands)==0) if(filename.empty() || clang_CompileCommands_getSize(cx_commands) == 0)
cx_commands = clang_CompilationDatabase_getAllCompileCommands(db.cx_db); cx_commands = clang_CompilationDatabase_getAllCompileCommands(db.cx_db);
} }
@ -15,7 +15,7 @@ std::vector<clangmm::CompileCommand> clangmm::CompileCommands::get_commands() {
unsigned size = clang_CompileCommands_getSize(cx_commands); unsigned size = clang_CompileCommands_getSize(cx_commands);
std::vector<CompileCommand> commands; std::vector<CompileCommand> commands;
commands.reserve(size); commands.reserve(size);
for (unsigned i = 0; i < size; i++) for(unsigned i = 0; i < size; i++)
commands.emplace_back(clang_CompileCommands_getCommand(cx_commands, i)); commands.emplace_back(clang_CompileCommands_getCommand(cx_commands, i));
return commands; return commands;
} }

4
src/compile_commands.h

@ -15,5 +15,5 @@ namespace clangmm {
CXCompileCommands cx_commands; CXCompileCommands cx_commands;
}; };
} } // namespace clangmm
#endif // COMPILECOMMANDS_H_ #endif // COMPILECOMMANDS_H_

90
src/completion_string.cc

@ -39,96 +39,96 @@ clangmm::Cursor clangmm::CompletionString::get_cursor(CXTranslationUnit &tu) con
public: public:
static void remove_template_argument_and_namespace(std::string &chunk) { static void remove_template_argument_and_namespace(std::string &chunk) {
size_t pos1, pos2; size_t pos1, pos2;
if((pos1=chunk.find('<'))!=std::string::npos && (pos2=chunk.rfind('>'))!=std::string::npos) if((pos1 = chunk.find('<')) != std::string::npos && (pos2 = chunk.rfind('>')) != std::string::npos)
chunk=chunk.substr(0, pos1)+chunk.substr(pos2+1); chunk = chunk.substr(0, pos1) + chunk.substr(pos2 + 1);
if((pos2=chunk.rfind("::"))!=std::string::npos) { if((pos2 = chunk.rfind("::")) != std::string::npos) {
pos1=pos2-1; pos1 = pos2 - 1;
while(pos1!=std::string::npos && ((chunk[pos1]>='a' && chunk[pos1]<='z') || (chunk[pos1]>='A' && chunk[pos1]<='Z') || while(pos1 != std::string::npos && ((chunk[pos1] >= 'a' && chunk[pos1] <= 'z') || (chunk[pos1] >= 'A' && chunk[pos1] <= 'Z') ||
(chunk[pos1]>='0' && chunk[pos1]<='9') || chunk[pos1]==':' || chunk[pos1]=='_')) (chunk[pos1] >= '0' && chunk[pos1] <= '9') || chunk[pos1] == ':' || chunk[pos1] == '_'))
--pos1; --pos1;
chunk=chunk.substr(0, pos1+1)+chunk.substr(pos2+2); chunk = chunk.substr(0, pos1 + 1) + chunk.substr(pos2 + 2);
} }
} }
}; };
std::vector<std::string> chunks; std::vector<std::string> chunks;
for(unsigned i=0;i<clang_getNumCompletionChunks(cx_completion_string);++i) { for(unsigned i = 0; i < clang_getNumCompletionChunks(cx_completion_string); ++i) {
auto kind = clang_getCompletionChunkKind(cx_completion_string, i); auto kind = clang_getCompletionChunkKind(cx_completion_string, i);
if(kind != CXCompletionChunk_Optional && kind != CXCompletionChunk_Informative) { if(kind != CXCompletionChunk_Optional && kind != CXCompletionChunk_Informative) {
auto chunk=clangmm::to_string(clang_getCompletionChunkText(cx_completion_string, i)); auto chunk = clangmm::to_string(clang_getCompletionChunkText(cx_completion_string, i));
ChunkString::remove_template_argument_and_namespace(chunk); ChunkString::remove_template_argument_and_namespace(chunk);
chunks.emplace_back(chunk); chunks.emplace_back(chunk);
} }
} }
auto parent=clangmm::to_string(clang_getCompletionParent(cx_completion_string, nullptr)); auto parent = clangmm::to_string(clang_getCompletionParent(cx_completion_string, nullptr));
std::vector<std::string> parent_parts; std::vector<std::string> parent_parts;
if(!parent.empty()) { if(!parent.empty()) {
size_t pos=0; size_t pos = 0;
size_t last_pos=0; size_t last_pos = 0;
while((pos=parent.find("::", pos))!=std::string::npos) { while((pos = parent.find("::", pos)) != std::string::npos) {
parent_parts.emplace_back(parent.substr(last_pos, pos-last_pos)); parent_parts.emplace_back(parent.substr(last_pos, pos - last_pos));
pos+=2; pos += 2;
last_pos=pos; last_pos = pos;
} }
parent_parts.emplace_back(parent.substr(last_pos)); parent_parts.emplace_back(parent.substr(last_pos));
} }
VisitorData visitor_data{chunks, parent_parts, clangmm::Cursor()}; VisitorData visitor_data{chunks, parent_parts, clangmm::Cursor()};
clang_visitChildren(clang_getTranslationUnitCursor(tu), [](CXCursor cx_cursor, CXCursor cx_parent, CXClientData cx_data) { clang_visitChildren(clang_getTranslationUnitCursor(tu), [](CXCursor cx_cursor, CXCursor cx_parent, CXClientData cx_data) {
auto data = static_cast<VisitorData *>(cx_data); auto data = static_cast<VisitorData *>(cx_data);
bool equal=true; bool equal = true;
auto cx_tmp_cursor=cx_parent; auto cx_tmp_cursor = cx_parent;
if(clang_getCursorKind(cx_tmp_cursor)!=CXCursorKind::CXCursor_TranslationUnit) { if(clang_getCursorKind(cx_tmp_cursor) != CXCursorKind::CXCursor_TranslationUnit) {
int c=0; int c = 0;
auto it=data->parent_parts.rbegin(); auto it = data->parent_parts.rbegin();
for(;it!=data->parent_parts.rend();++it) { for(; it != data->parent_parts.rend(); ++it) {
auto name=clangmm::to_string(clang_getCursorDisplayName(cx_tmp_cursor)); auto name = clangmm::to_string(clang_getCursorDisplayName(cx_tmp_cursor));
size_t pos; size_t pos;
if((pos=name.find('<'))!=std::string::npos) if((pos = name.find('<')) != std::string::npos)
name=name.substr(0, pos); name = name.substr(0, pos);
if(name!=*it) { if(name != *it) {
equal=false; equal = false;
break; break;
} }
cx_tmp_cursor=clang_getCursorSemanticParent(cx_tmp_cursor); cx_tmp_cursor = clang_getCursorSemanticParent(cx_tmp_cursor);
if(clang_getCursorKind(cx_tmp_cursor)==CXCursorKind::CXCursor_TranslationUnit) { if(clang_getCursorKind(cx_tmp_cursor) == CXCursorKind::CXCursor_TranslationUnit) {
++it; ++it;
break; break;
} }
++c; ++c;
} }
if(it!=data->parent_parts.rend()) if(it != data->parent_parts.rend())
equal=false; equal = false;
} }
else if(!data->parent_parts.empty()) else if(!data->parent_parts.empty())
return CXChildVisit_Recurse; return CXChildVisit_Recurse;
if(equal) { if(equal) {
auto completion_string = clang_getCursorCompletionString(cx_cursor); auto completion_string = clang_getCursorCompletionString(cx_cursor);
auto num_completion_chunks=clang_getNumCompletionChunks(completion_string); auto num_completion_chunks = clang_getNumCompletionChunks(completion_string);
if(num_completion_chunks>=data->completion_chunks.size()) { if(num_completion_chunks >= data->completion_chunks.size()) {
bool equal=true; bool equal = true;
for(unsigned i=0;i<data->completion_chunks.size() && i<num_completion_chunks;++i) { for(unsigned i = 0; i < data->completion_chunks.size() && i < num_completion_chunks; ++i) {
auto kind = clang_getCompletionChunkKind(completion_string, i); auto kind = clang_getCompletionChunkKind(completion_string, i);
if(kind != CXCompletionChunk_Optional && kind != CXCompletionChunk_Informative) { if(kind != CXCompletionChunk_Optional && kind != CXCompletionChunk_Informative) {
auto chunk=clangmm::to_string(clang_getCompletionChunkText(completion_string, i)); auto chunk = clangmm::to_string(clang_getCompletionChunkText(completion_string, i));
ChunkString::remove_template_argument_and_namespace(chunk); ChunkString::remove_template_argument_and_namespace(chunk);
if(data->completion_chunks[i]!=chunk) { if(data->completion_chunks[i] != chunk) {
equal=false; equal = false;
break; break;
} }
} }
} }
if(equal) { if(equal) {
data->found_cursor=cx_cursor; data->found_cursor = cx_cursor;
return CXChildVisit_Break; return CXChildVisit_Break;
} }
} }
} }
return CXChildVisit_Recurse; return CXChildVisit_Recurse;
}, &visitor_data); }, &visitor_data);
return Cursor(visitor_data.found_cursor); return Cursor(visitor_data.found_cursor);
} }

12
src/completion_string.h

@ -1,13 +1,13 @@
#ifndef COMPLETIONSTRING_H_ #ifndef COMPLETIONSTRING_H_
#define COMPLETIONSTRING_H_ #define COMPLETIONSTRING_H_
#include "cursor.h"
#include <clang-c/Index.h> #include <clang-c/Index.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include "cursor.h"
namespace clangmm { namespace clangmm {
enum CompletionChunkKind { enum CompletionChunkKind {
CompletionChunk_Optional, CompletionChunk_TypedText, CompletionChunk_Optional, CompletionChunk_TypedText,
CompletionChunk_Text, CompletionChunk_Placeholder, CompletionChunk_Text, CompletionChunk_Placeholder,
CompletionChunk_Informative, CompletionChunk_CurrentParameter, CompletionChunk_Informative, CompletionChunk_CurrentParameter,
CompletionChunk_LeftParen, CompletionChunk_RightParen, CompletionChunk_LeftParen, CompletionChunk_RightParen,
@ -34,11 +34,11 @@ namespace clangmm {
std::vector<CompletionChunk> get_chunks() const; std::vector<CompletionChunk> get_chunks() const;
unsigned get_num_chunks() const; unsigned get_num_chunks() const;
std::string get_brief_comment() const; std::string get_brief_comment() const;
/// Search for the corresponding cursor /// Search for the corresponding cursor
Cursor get_cursor(CXTranslationUnit &tu) const; Cursor get_cursor(CXTranslationUnit &tu) const;
CXCompletionString cx_completion_string; CXCompletionString cx_completion_string;
}; };
} // namespace clangmm } // namespace clangmm
#endif // COMPLETIONSTRING_H_ #endif // COMPLETIONSTRING_H_

153
src/cursor.cc

@ -14,7 +14,7 @@ clangmm::Cursor clangmm::Cursor::Type::get_cursor() const {
return Cursor(clang_getTypeDeclaration(cx_type)); return Cursor(clang_getTypeDeclaration(cx_type));
} }
bool clangmm::Cursor::Type::operator==(const Cursor::Type& rhs) const { bool clangmm::Cursor::Type::operator==(const Cursor::Type &rhs) const {
return clang_equalTypes(cx_type, rhs.cx_type); return clang_equalTypes(cx_type, rhs.cx_type);
} }
@ -27,24 +27,24 @@ std::string clangmm::Cursor::get_kind_spelling() const {
} }
bool clangmm::Cursor::is_similar_kind(Kind kind, Kind other_kind) { bool clangmm::Cursor::is_similar_kind(Kind kind, Kind other_kind) {
auto is_function_or_method=[](Kind kind) { auto is_function_or_method = [](Kind kind) {
if(kind==Kind::FunctionDecl || kind==Kind::CXXMethod || kind==Kind::FunctionTemplate) if(kind == Kind::FunctionDecl || kind == Kind::CXXMethod || kind == Kind::FunctionTemplate)
return true; return true;
return false; return false;
}; };
auto is_class_or_struct=[](Kind kind) { auto is_class_or_struct = [](Kind kind) {
if(kind==Kind::ClassDecl || kind==Kind::StructDecl || kind==Kind::ClassTemplate || if(kind == Kind::ClassDecl || kind == Kind::StructDecl || kind == Kind::ClassTemplate ||
kind==Cursor::Kind::Constructor || kind==Cursor::Kind::Destructor || kind==Cursor::Kind::FunctionTemplate) kind == Cursor::Kind::Constructor || kind == Cursor::Kind::Destructor || kind == Cursor::Kind::FunctionTemplate)
return true; return true;
return false; return false;
}; };
if(kind==Kind::FunctionTemplate) if(kind == Kind::FunctionTemplate)
return is_function_or_method(other_kind) || is_class_or_struct(other_kind); return is_function_or_method(other_kind) || is_class_or_struct(other_kind);
if(is_function_or_method(kind)) if(is_function_or_method(kind))
return is_function_or_method(other_kind); return is_function_or_method(other_kind);
if(is_class_or_struct(kind)) if(is_class_or_struct(kind))
return is_class_or_struct(other_kind); return is_class_or_struct(other_kind);
return kind==other_kind; return kind == other_kind;
} }
clangmm::Cursor::Type clangmm::Cursor::get_type() const { clangmm::Cursor::Type clangmm::Cursor::get_type() const {
@ -68,15 +68,15 @@ std::string clangmm::Cursor::get_display_name() const {
} }
std::string clangmm::Cursor::get_token_spelling() const { std::string clangmm::Cursor::get_token_spelling() const {
auto spelling=get_spelling(); auto spelling = get_spelling();
for(size_t i=0;i<spelling.size();++i) { for(size_t i = 0; i < spelling.size(); ++i) {
if(spelling[i]=='<' || spelling[i]=='(') { if(spelling[i] == '<' || spelling[i] == '(') {
if(i>0 && spelling[0]=='~') if(i > 0 && spelling[0] == '~')
return spelling.substr(1, i-1); return spelling.substr(1, i - 1);
return spelling.substr(0, i); return spelling.substr(0, i);
} }
} }
if(!spelling.empty() && spelling[0]=='~') if(!spelling.empty() && spelling[0] == '~')
return spelling.substr(1); return spelling.substr(1);
return spelling; return spelling;
} }
@ -88,38 +88,38 @@ std::string clangmm::Cursor::get_usr() const {
std::string clangmm::Cursor::get_usr_extended() const { std::string clangmm::Cursor::get_usr_extended() const {
if(!is_valid_kind()) if(!is_valid_kind())
return std::string(); return std::string();
auto cursor=*this; auto cursor = *this;
auto kind=cursor.get_kind(); auto kind = cursor.get_kind();
// If constructor, destructor or function template, and the token spelling is equal, set cursor to parent // If constructor, destructor or function template, and the token spelling is equal, set cursor to parent
if(kind==Cursor::Kind::Constructor || kind==Cursor::Kind::Destructor || if(kind == Cursor::Kind::Constructor || kind == Cursor::Kind::Destructor ||
kind==Cursor::Kind::FunctionTemplate) { kind == Cursor::Kind::FunctionTemplate) {
auto parent=cursor.get_semantic_parent(); auto parent = cursor.get_semantic_parent();
auto parent_kind=parent.get_kind(); auto parent_kind = parent.get_kind();
if((parent_kind==Cursor::Kind::ClassDecl || parent_kind==Cursor::Kind::StructDecl || parent_kind==Cursor::Kind::ClassTemplate) && if((parent_kind == Cursor::Kind::ClassDecl || parent_kind == Cursor::Kind::StructDecl || parent_kind == Cursor::Kind::ClassTemplate) &&
cursor.get_token_spelling()==parent.get_token_spelling()) cursor.get_token_spelling() == parent.get_token_spelling())
cursor=parent; cursor = parent;
} }
std::string usr=cursor.get_token_spelling(); std::string usr = cursor.get_token_spelling();
auto parent=cursor.get_semantic_parent(); auto parent = cursor.get_semantic_parent();
while((kind=parent.get_kind())!=Kind::TranslationUnit && parent.is_valid_kind()) { while((kind = parent.get_kind()) != Kind::TranslationUnit && parent.is_valid_kind()) {
if(kind==Kind::CXXMethod || kind==Kind::FunctionDecl || kind==Kind::FunctionTemplate || if(kind == Kind::CXXMethod || kind == Kind::FunctionDecl || kind == Kind::FunctionTemplate ||
kind==Kind::Constructor || kind==Kind::Destructor) { kind == Kind::Constructor || kind == Kind::Destructor) {
auto canonical=cursor.get_canonical(); auto canonical = cursor.get_canonical();
auto location=canonical.get_source_location(); auto location = canonical.get_source_location();
auto offset=location.get_offset(); auto offset = location.get_offset();
return std::to_string(offset.line)+':'+std::to_string(offset.index)+':'+location.get_path(); return std::to_string(offset.line) + ':' + std::to_string(offset.index) + ':' + location.get_path();
} }
usr+=':'+parent.get_token_spelling(); usr += ':' + parent.get_token_spelling();
parent=parent.get_semantic_parent(); parent = parent.get_semantic_parent();
} }
return usr; return usr;
} }
std::unordered_set<std::string> clangmm::Cursor::get_all_usr_extended() const { std::unordered_set<std::string> clangmm::Cursor::get_all_usr_extended() const {
std::unordered_set<std::string> usrs; std::unordered_set<std::string> usrs;
if(get_kind()==Kind::CXXMethod) { if(get_kind() == Kind::CXXMethod) {
class Recursive { class Recursive {
public: public:
static void overridden(std::unordered_set<std::string> &usrs, const Cursor &cursor) { static void overridden(std::unordered_set<std::string> &usrs, const Cursor &cursor) {
@ -127,7 +127,7 @@ std::unordered_set<std::string> clangmm::Cursor::get_all_usr_extended() const {
CXCursor *cursors; CXCursor *cursors;
unsigned size; unsigned size;
clang_getOverriddenCursors(cursor.cx_cursor, &cursors, &size); clang_getOverriddenCursors(cursor.cx_cursor, &cursors, &size);
for(unsigned c=0;c<size;++c) for(unsigned c = 0; c < size; ++c)
overridden(usrs, cursors[c]); overridden(usrs, cursors[c]);
clang_disposeOverriddenCursors(cursors); clang_disposeOverriddenCursors(cursors);
} }
@ -159,39 +159,36 @@ clangmm::Cursor clangmm::Cursor::get_semantic_parent() const {
std::vector<clangmm::Cursor> clangmm::Cursor::get_children() const { std::vector<clangmm::Cursor> clangmm::Cursor::get_children() const {
std::vector<Cursor> result; std::vector<Cursor> result;
clang_visitChildren(cx_cursor, clang_visitChildren(cx_cursor, [](CXCursor cur, CXCursor /*parent*/, CXClientData data) {
[](CXCursor cur, CXCursor /*parent*/, CXClientData data) { static_cast<std::vector<Cursor> *>(data)->emplace_back(cur);
static_cast<std::vector<Cursor>*>(data)->emplace_back(cur); return CXChildVisit_Continue;
return CXChildVisit_Continue; }, &result);
},
&result
);
return result; return result;
} }
std::vector<clangmm::Cursor> clangmm::Cursor::get_arguments() const { std::vector<clangmm::Cursor> clangmm::Cursor::get_arguments() const {
std::vector<Cursor> cursors; std::vector<Cursor> cursors;
auto size=clang_Cursor_getNumArguments(cx_cursor); auto size = clang_Cursor_getNumArguments(cx_cursor);
for(int c=0;c<size;++c) for(int c = 0; c < size; ++c)
cursors.emplace_back(clang_Cursor_getArgument(cx_cursor, c)); cursors.emplace_back(clang_Cursor_getArgument(cx_cursor, c));
return cursors; return cursors;
} }
std::vector<clangmm::Cursor> clangmm::Cursor::get_all_overridden_cursors() const { std::vector<clangmm::Cursor> clangmm::Cursor::get_all_overridden_cursors() const {
std::vector<Cursor> result; std::vector<Cursor> result;
if(get_kind()!=Kind::CXXMethod) if(get_kind() != Kind::CXXMethod)
return result; return result;
class Recursive { class Recursive {
public: public:
static void overridden(std::vector<Cursor> &result, const Cursor &cursor, int depth) { static void overridden(std::vector<Cursor> &result, const Cursor &cursor, int depth) {
if(depth>0) if(depth > 0)
result.emplace_back(cursor); result.emplace_back(cursor);
CXCursor *cursors; CXCursor *cursors;
unsigned size; unsigned size;
clang_getOverriddenCursors(cursor.cx_cursor, &cursors, &size); clang_getOverriddenCursors(cursor.cx_cursor, &cursors, &size);
for(unsigned c=0;c<size;++c) for(unsigned c = 0; c < size; ++c)
overridden(result, cursors[c], depth+1); overridden(result, cursors[c], depth + 1);
clang_disposeOverriddenCursors(cursors); clang_disposeOverriddenCursors(cursors);
} }
}; };
@ -203,7 +200,7 @@ clangmm::Cursor::operator bool() const {
return !clang_Cursor_isNull(cx_cursor); return !clang_Cursor_isNull(cx_cursor);
} }
bool clangmm::Cursor::operator==(const Cursor& rhs) const { bool clangmm::Cursor::operator==(const Cursor &rhs) const {
return clang_equalCursors(cx_cursor, rhs.cx_cursor); return clang_equalCursors(cx_cursor, rhs.cx_cursor);
} }
@ -212,54 +209,54 @@ unsigned clangmm::Cursor::hash() const {
} }
bool clangmm::Cursor::is_valid_kind() const { bool clangmm::Cursor::is_valid_kind() const {
auto referenced=clang_getCursorReferenced(cx_cursor); auto referenced = clang_getCursorReferenced(cx_cursor);
if(clang_Cursor_isNull(referenced)) if(clang_Cursor_isNull(referenced))
return false; return false;
auto kind=get_kind(); auto kind = get_kind();
return kind>Kind::UnexposedDecl && (kind<Kind::FirstInvalid || kind>Kind::LastInvalid); return kind > Kind::UnexposedDecl && (kind < Kind::FirstInvalid || kind > Kind::LastInvalid);
} }
std::string clangmm::Cursor::get_type_description() const { std::string clangmm::Cursor::get_type_description() const {
std::string spelling; std::string spelling;
auto referenced=clang_getCursorReferenced(cx_cursor); auto referenced = clang_getCursorReferenced(cx_cursor);
if(!clang_Cursor_isNull(referenced)) { if(!clang_Cursor_isNull(referenced)) {
auto type=clang_getCursorType(referenced); auto type = clang_getCursorType(referenced);
spelling=to_string(clang_getTypeSpelling(type)); spelling = to_string(clang_getTypeSpelling(type));
#if CINDEX_VERSION_MAJOR==0 && CINDEX_VERSION_MINOR<32 #if CINDEX_VERSION_MAJOR == 0 && CINDEX_VERSION_MINOR < 32
const std::string auto_str="auto"; const std::string auto_str = "auto";
if(spelling.size()>=4 && std::equal(auto_str.begin(), auto_str.end(), spelling.begin())) { if(spelling.size() >= 4 && std::equal(auto_str.begin(), auto_str.end(), spelling.begin())) {
auto canonical_type=clang_getCanonicalType(clang_getCursorType(cx_cursor)); auto canonical_type = clang_getCanonicalType(clang_getCursorType(cx_cursor));
auto canonical_spelling=to_string(clang_getTypeSpelling(canonical_type)); auto canonical_spelling = to_string(clang_getTypeSpelling(canonical_type));
if(spelling.size()>5 && spelling[4]==' ' && spelling[5]=='&' && spelling!=canonical_spelling) if(spelling.size() > 5 && spelling[4] == ' ' && spelling[5] == '&' && spelling != canonical_spelling)
return canonical_spelling+" &"; return canonical_spelling + " &";
else else
return canonical_spelling; return canonical_spelling;
} }
const std::string const_auto_str="const auto"; const std::string const_auto_str = "const auto";
if(spelling.size()>=10 && std::equal(const_auto_str.begin(), const_auto_str.end(), spelling.begin())) { if(spelling.size() >= 10 && std::equal(const_auto_str.begin(), const_auto_str.end(), spelling.begin())) {
auto canonical_type=clang_getCanonicalType(clang_getCursorType(cx_cursor)); auto canonical_type = clang_getCanonicalType(clang_getCursorType(cx_cursor));
auto canonical_spelling=to_string(clang_getTypeSpelling(canonical_type)); auto canonical_spelling = to_string(clang_getTypeSpelling(canonical_type));
if(spelling.size()>11 && spelling[10]==' ' && spelling[11]=='&' && spelling!=canonical_spelling) if(spelling.size() > 11 && spelling[10] == ' ' && spelling[11] == '&' && spelling != canonical_spelling)
return canonical_spelling+" &"; return canonical_spelling + " &";
else else
return canonical_spelling; return canonical_spelling;
} }
#endif #endif
} }
if(spelling.empty()) if(spelling.empty())
return get_spelling(); return get_spelling();
return spelling; return spelling;
} }
std::string clangmm::Cursor::get_brief_comments() const { std::string clangmm::Cursor::get_brief_comments() const {
std::string comment_string; std::string comment_string;
auto referenced=get_referenced(); auto referenced = get_referenced();
if(referenced) { if(referenced) {
comment_string=to_string(clang_Cursor_getBriefCommentText(referenced.cx_cursor)); comment_string = to_string(clang_Cursor_getBriefCommentText(referenced.cx_cursor));
} }
return comment_string; return comment_string;
} }

24
src/cursor.h

@ -1,11 +1,11 @@
#ifndef CURSOR_H_ #ifndef CURSOR_H_
#define CURSOR_H_ #define CURSOR_H_
#include <clang-c/Index.h>
#include "source_location.h" #include "source_location.h"
#include "source_range.h" #include "source_range.h"
#include <clang-c/Index.h>
#include <string> #include <string>
#include <vector>
#include <unordered_set> #include <unordered_set>
#include <vector>
namespace clangmm { namespace clangmm {
class Cursor { class Cursor {
@ -183,12 +183,12 @@ namespace clangmm {
std::string get_spelling() const; std::string get_spelling() const;
Type get_result() const; Type get_result() const;
Cursor get_cursor() const; Cursor get_cursor() const;
bool operator==(const Cursor::Type& rhs) const; bool operator==(const Cursor::Type &rhs) const;
CXType cx_type; CXType cx_type;
}; };
Cursor() { cx_cursor=clang_getNullCursor(); } Cursor() { cx_cursor = clang_getNullCursor(); }
Cursor(const CXCursor &cx_cursor) : cx_cursor(cx_cursor) {} Cursor(const CXCursor &cx_cursor) : cx_cursor(cx_cursor) {}
Kind get_kind() const; Kind get_kind() const;
std::string get_kind_spelling() const; std::string get_kind_spelling() const;
@ -212,19 +212,19 @@ namespace clangmm {
std::vector<Cursor> get_arguments() const; std::vector<Cursor> get_arguments() const;
std::vector<Cursor> get_all_overridden_cursors() const; std::vector<Cursor> get_all_overridden_cursors() const;
operator bool() const; operator bool() const;
bool operator==(const Cursor& rhs) const; bool operator==(const Cursor &rhs) const;
unsigned hash() const; unsigned hash() const;
bool is_valid_kind() const; bool is_valid_kind() const;
std::string get_type_description() const; std::string get_type_description() const;
std::string get_brief_comments() const; std::string get_brief_comments() const;
friend std::ostream &operator<<(std::ostream &os, const Cursor &cursor) { friend std::ostream &operator<<(std::ostream &os, const Cursor &cursor) {
os << cursor.get_source_range() << ' ' << cursor.get_spelling(); os << cursor.get_source_range() << ' ' << cursor.get_spelling();
return os; return os;
} }
CXCursor cx_cursor; CXCursor cx_cursor;
}; };
} // namespace clangmm } // namespace clangmm
#endif // CURSOR_H_ #endif // CURSOR_H_

26
src/diagnostic.cc

@ -3,22 +3,22 @@
#include "tokens.h" #include "tokens.h"
#include "utility.h" #include "utility.h"
clangmm::Diagnostic::Diagnostic(CXTranslationUnit& cx_tu, CXDiagnostic& cx_diagnostic) { clangmm::Diagnostic::Diagnostic(CXTranslationUnit &cx_tu, CXDiagnostic &cx_diagnostic) {
severity=static_cast<Severity>(clang_getDiagnosticSeverity(cx_diagnostic)); severity = static_cast<Severity>(clang_getDiagnosticSeverity(cx_diagnostic));
spelling=to_string(clang_getDiagnosticSpelling(cx_diagnostic)); spelling = to_string(clang_getDiagnosticSpelling(cx_diagnostic));
SourceLocation location(clang_getDiagnosticLocation(cx_diagnostic)); SourceLocation location(clang_getDiagnosticLocation(cx_diagnostic));
path=location.get_path(); path = location.get_path();
auto offset=location.get_offset(); auto offset = location.get_offset();
auto corrected_location=SourceLocation(cx_tu, path.c_str(), offset.line, offset.index); // to avoid getting macro tokens auto corrected_location = SourceLocation(cx_tu, path.c_str(), offset.line, offset.index); // to avoid getting macro tokens
Tokens tokens(cx_tu, SourceRange(corrected_location, corrected_location), false); Tokens tokens(cx_tu, SourceRange(corrected_location, corrected_location), false);
if(tokens.size()==1) if(tokens.size() == 1)
offsets={offset, tokens.begin()->get_source_range().get_offsets().second}; offsets = {offset, tokens.begin()->get_source_range().get_offsets().second};
unsigned num_fix_its=clang_getDiagnosticNumFixIts(cx_diagnostic); unsigned num_fix_its = clang_getDiagnosticNumFixIts(cx_diagnostic);
for(unsigned c=0;c<num_fix_its;c++) { for(unsigned c = 0; c < num_fix_its; c++) {
CXSourceRange fix_it_range; CXSourceRange fix_it_range;
auto source=to_string(clang_getDiagnosticFixIt(cx_diagnostic, c, &fix_it_range)); auto source = to_string(clang_getDiagnosticFixIt(cx_diagnostic, c, &fix_it_range));
fix_its.emplace_back(source, SourceRange(fix_it_range).get_offsets()); fix_its.emplace_back(source, SourceRange(fix_it_range).get_offsets());
} }
} }

17
src/diagnostic.h

@ -1,14 +1,15 @@
#ifndef DIAGNOSTIC_H_ #ifndef DIAGNOSTIC_H_
#define DIAGNOSTIC_H_ #define DIAGNOSTIC_H_
#include "source_range.h"
#include <clang-c/Index.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include <clang-c/Index.h>
#include "source_range.h"
namespace clangmm { namespace clangmm {
class Diagnostic { class Diagnostic {
friend class TranslationUnit; friend class TranslationUnit;
Diagnostic(CXTranslationUnit& cx_tu, CXDiagnostic& cx_diagnostic); Diagnostic(CXTranslationUnit &cx_tu, CXDiagnostic &cx_diagnostic);
public: public:
enum class Severity { enum class Severity {
Ignored = 0, Ignored = 0,
@ -17,11 +18,11 @@ namespace clangmm {
Error, Error,
Fatal Fatal
}; };
class FixIt { class FixIt {
public: public:
FixIt(const std::string &source, const std::pair<clangmm::Offset, clangmm::Offset> &offsets): FixIt(const std::string &source, const std::pair<clangmm::Offset, clangmm::Offset> &offsets)
source(source), offsets(offsets) {} : source(source), offsets(offsets) {}
std::string source; std::string source;
std::pair<clangmm::Offset, clangmm::Offset> offsets; std::pair<clangmm::Offset, clangmm::Offset> offsets;
}; };
@ -32,6 +33,6 @@ namespace clangmm {
std::pair<clangmm::Offset, clangmm::Offset> offsets; std::pair<clangmm::Offset, clangmm::Offset> offsets;
std::vector<FixIt> fix_its; std::vector<FixIt> fix_its;
}; };
} } // namespace clangmm
#endif // DIAGNOSTIC_H_ #endif // DIAGNOSTIC_H_

4
src/index.h

@ -9,5 +9,5 @@ namespace clangmm {
~Index(); ~Index();
CXIndex cx_index; CXIndex cx_index;
}; };
} // namespace clangmm } // namespace clangmm
#endif // INDEX_H_ #endif // INDEX_H_

9
src/source_location.cc

@ -25,15 +25,14 @@ clangmm::Offset clangmm::SourceLocation::get_offset() const {
return {line, index}; return {line, index};
} }
void clangmm::SourceLocation::get_data(std::string* path, unsigned *line, unsigned *column, unsigned *offset) const { void clangmm::SourceLocation::get_data(std::string *path, unsigned *line, unsigned *column, unsigned *offset) const {
if(path==nullptr) if(path == nullptr)
clang_getExpansionLocation(cx_location, NULL, line, column, offset); clang_getExpansionLocation(cx_location, NULL, line, column, offset);
else { else {
CXFile file; CXFile file;
clang_getExpansionLocation(cx_location, &file, line, column, offset); clang_getExpansionLocation(cx_location, &file, line, column, offset);
if (file!=NULL) { if(file != NULL) {
*path=to_string(clang_getFileName(file)); *path = to_string(clang_getFileName(file));
} }
} }
} }

27
src/source_location.h

@ -1,45 +1,46 @@
#ifndef SOURCELOCATION_H_ #ifndef SOURCELOCATION_H_
#define SOURCELOCATION_H_ #define SOURCELOCATION_H_
#include <clang-c/Index.h> #include <clang-c/Index.h>
#include <string>
#include <ostream> #include <ostream>
#include <string>
namespace clangmm { namespace clangmm {
class Offset { class Offset {
public: public:
bool operator==(const Offset &o) const {return line==o.line && index==o.index;} bool operator==(const Offset &o) const { return line == o.line && index == o.index; }
bool operator!=(const Offset &o) const {return !(*this==o);} bool operator!=(const Offset &o) const { return !(*this == o); }
bool operator<(const Offset &o) const {return line<o.line || (line==o.line && index<o.index);} bool operator<(const Offset &o) const { return line < o.line || (line == o.line && index < o.index); }
bool operator>(const Offset &o) const {return o < *this;} bool operator>(const Offset &o) const { return o < *this; }
bool operator<=(const Offset &o) const {return (*this == o) || (*this < o);} bool operator<=(const Offset &o) const { return (*this == o) || (*this < o); }
bool operator>=(const Offset &o) const {return (*this == o) || (*this > o);} bool operator>=(const Offset &o) const { return (*this == o) || (*this > o); }
unsigned line; unsigned line;
unsigned index; //byte index in line (not char number) unsigned index; //byte index in line (not char number)
}; };
class SourceLocation { class SourceLocation {
friend class TranslationUnit; friend class TranslationUnit;
friend class Diagnostic; friend class Diagnostic;
SourceLocation(CXTranslationUnit &tu, const std::string &filepath, unsigned offset); SourceLocation(CXTranslationUnit &tu, const std::string &filepath, unsigned offset);
SourceLocation(CXTranslationUnit &tu, const std::string &filepath, unsigned line, unsigned column); SourceLocation(CXTranslationUnit &tu, const std::string &filepath, unsigned line, unsigned column);
public: public:
SourceLocation(const CXSourceLocation& cx_location) : cx_location(cx_location) {} SourceLocation(const CXSourceLocation &cx_location) : cx_location(cx_location) {}
public: public:
std::string get_path() const; std::string get_path() const;
clangmm::Offset get_offset() const; clangmm::Offset get_offset() const;
friend std::ostream &operator<<(std::ostream &os, const SourceLocation &location) { friend std::ostream &operator<<(std::ostream &os, const SourceLocation &location) {
auto offset=location.get_offset(); auto offset = location.get_offset();
os << location.get_path() << ':' << offset.line << ':' << offset.index; os << location.get_path() << ':' << offset.line << ':' << offset.index;
return os; return os;
} }
CXSourceLocation cx_location; CXSourceLocation cx_location;
private: private:
void get_data(std::string *path, unsigned *line, unsigned *column, unsigned *offset) const; void get_data(std::string *path, unsigned *line, unsigned *column, unsigned *offset) const;
}; };
} // namespace clangmm } // namespace clangmm
#endif // SOURCELOCATION_H_ #endif // SOURCELOCATION_H_

14
src/source_range.h

@ -1,25 +1,25 @@
#ifndef SOURCERANGE_H_ #ifndef SOURCERANGE_H_
#define SOURCERANGE_H_ #define SOURCERANGE_H_
#include <clang-c/Index.h>
#include "source_location.h" #include "source_location.h"
#include <clang-c/Index.h>
#include <string> #include <string>
#include <utility> #include <utility>
namespace clangmm { namespace clangmm {
class SourceRange { class SourceRange {
public: public:
SourceRange(const CXSourceRange& cx_range) : cx_range(cx_range) {} SourceRange(const CXSourceRange &cx_range) : cx_range(cx_range) {}
SourceRange(const SourceLocation &start, const SourceLocation &end); SourceRange(const SourceLocation &start, const SourceLocation &end);
SourceLocation get_start() const; SourceLocation get_start() const;
SourceLocation get_end() const; SourceLocation get_end() const;
std::pair<clangmm::Offset, clangmm::Offset> get_offsets() const; std::pair<clangmm::Offset, clangmm::Offset> get_offsets() const;
friend std::ostream &operator<<(std::ostream &os, const SourceRange &range) { friend std::ostream &operator<<(std::ostream &os, const SourceRange &range) {
os << range.get_start() << '-' << range.get_end(); os << range.get_start() << '-' << range.get_end();
return os; return os;
} }
CXSourceRange cx_range; CXSourceRange cx_range;
}; };
} // namespace clangmm } // namespace clangmm
#endif // SOURCERANGE_H_ #endif // SOURCERANGE_H_

20
src/token.cc

@ -25,20 +25,20 @@ clangmm::Token::Kind clangmm::Token::get_kind() const {
} }
bool clangmm::Token::is_identifier() const { bool clangmm::Token::is_identifier() const {
auto token_kind=get_kind(); auto token_kind = get_kind();
auto cursor=get_cursor(); auto cursor = get_cursor();
if(token_kind==clangmm::Token::Kind::Identifier && cursor.is_valid_kind()) if(token_kind == clangmm::Token::Kind::Identifier && cursor.is_valid_kind())
return true; return true;
else if(token_kind==clangmm::Token::Kind::Keyword && cursor.is_valid_kind()) { else if(token_kind == clangmm::Token::Kind::Keyword && cursor.is_valid_kind()) {
auto spelling=get_spelling(); auto spelling = get_spelling();
if(spelling=="operator" || (spelling=="bool" && get_cursor().get_spelling()=="operator bool")) if(spelling == "operator" || (spelling == "bool" && get_cursor().get_spelling() == "operator bool"))
return true; return true;
} }
else if(token_kind==clangmm::Token::Kind::Punctuation && cursor.is_valid_kind()) { else if(token_kind == clangmm::Token::Kind::Punctuation && cursor.is_valid_kind()) {
auto referenced=cursor.get_referenced(); auto referenced = cursor.get_referenced();
if(referenced) { if(referenced) {
auto referenced_kind=referenced.get_kind(); auto referenced_kind = referenced.get_kind();
if(referenced_kind==Cursor::Kind::FunctionDecl || referenced_kind==Cursor::Kind::CXXMethod || referenced_kind==Cursor::Kind::Constructor) if(referenced_kind == Cursor::Kind::FunctionDecl || referenced_kind == Cursor::Kind::CXXMethod || referenced_kind == Cursor::Kind::Constructor)
return true; return true;
} }
} }

23
src/token.h

@ -1,14 +1,15 @@
#ifndef TOKEN_H_ #ifndef TOKEN_H_
#define TOKEN_H_ #define TOKEN_H_
#include <clang-c/Index.h> #include "cursor.h"
#include "source_location.h" #include "source_location.h"
#include "source_range.h" #include "source_range.h"
#include "cursor.h" #include <clang-c/Index.h>
#include <string> #include <string>
namespace clangmm { namespace clangmm {
class Token { class Token {
friend class Tokens; friend class Tokens;
public: public:
enum Kind { enum Kind {
Punctuation, Punctuation,
@ -17,26 +18,28 @@ namespace clangmm {
Literal, Literal,
Comment Comment
}; };
private: private:
Token(CXTranslationUnit &cx_tu, CXToken &cx_token, CXCursor &cx_cursor): Token(CXTranslationUnit &cx_tu, CXToken &cx_token, CXCursor &cx_cursor)
cx_tu(cx_tu), cx_token(cx_token), cx_cursor(cx_cursor) {} : cx_tu(cx_tu), cx_token(cx_token), cx_cursor(cx_cursor) {}
public: public:
Kind get_kind() const; Kind get_kind() const;
std::string get_spelling() const; std::string get_spelling() const;
SourceLocation get_source_location() const; SourceLocation get_source_location() const;
SourceRange get_source_range() const; SourceRange get_source_range() const;
clangmm::Cursor get_cursor() const {return clangmm::Cursor(cx_cursor);} clangmm::Cursor get_cursor() const { return clangmm::Cursor(cx_cursor); }
bool is_identifier() const; bool is_identifier() const;
friend std::ostream &operator<<(std::ostream &os, const Token &token) { friend std::ostream &operator<<(std::ostream &os, const Token &token) {
os << token.get_source_range() << ' ' << token.get_spelling(); os << token.get_source_range() << ' ' << token.get_spelling();
return os; return os;
} }
CXTranslationUnit &cx_tu; CXTranslationUnit &cx_tu;
CXToken& cx_token; CXToken &cx_token;
CXCursor& cx_cursor; CXCursor &cx_cursor;
}; };
} // namespace clangmm } // namespace clangmm
#endif // TOKEN_H_ #endif // TOKEN_H_

84
src/tokens.cc

@ -1,42 +1,42 @@
#include "tokens.h" #include "tokens.h"
#include "utility.h" #include "utility.h"
#include <unordered_set>
#include <cstring> #include <cstring>
#include <map> #include <map>
#include <unordered_set>
clangmm::Tokens::Tokens(CXTranslationUnit &cx_tu, const SourceRange &range, bool annotate_tokens): cx_tu(cx_tu) { clangmm::Tokens::Tokens(CXTranslationUnit &cx_tu, const SourceRange &range, bool annotate_tokens) : cx_tu(cx_tu) {
unsigned num_tokens; unsigned num_tokens;
clang_tokenize(cx_tu, range.cx_range, &cx_tokens, &num_tokens); clang_tokenize(cx_tu, range.cx_range, &cx_tokens, &num_tokens);
if(!annotate_tokens) { if(!annotate_tokens) {
cx_cursors=std::unique_ptr<CXCursor[]>(new CXCursor[num_tokens]); cx_cursors = std::unique_ptr<CXCursor[]>(new CXCursor[num_tokens]);
for (unsigned i = 0; i < num_tokens; i++) { for(unsigned i = 0; i < num_tokens; i++) {
cx_cursors[i]=clang_getNullCursor(); cx_cursors[i] = clang_getNullCursor();
emplace_back(Token(cx_tu, cx_tokens[i], cx_cursors[i])); emplace_back(Token(cx_tu, cx_tokens[i], cx_cursors[i]));
} }
return; return;
} }
cx_cursors=std::unique_ptr<CXCursor[]>(new CXCursor[num_tokens]); // To avoid allocation with initialization cx_cursors = std::unique_ptr<CXCursor[]>(new CXCursor[num_tokens]); // To avoid allocation with initialization
clang_annotateTokens(cx_tu, cx_tokens, num_tokens, cx_cursors.get()); clang_annotateTokens(cx_tu, cx_tokens, num_tokens, cx_cursors.get());
bool tu_cursors=SourceRange(clang_getCursorExtent(clang_getTranslationUnitCursor(cx_tu))).get_start().get_path()==range.get_start().get_path(); bool tu_cursors = SourceRange(clang_getCursorExtent(clang_getTranslationUnitCursor(cx_tu))).get_start().get_path() == range.get_start().get_path();
std::map<size_t, Offset> invalid_tokens; std::map<size_t, Offset> invalid_tokens;
for (unsigned i = 0; i < num_tokens; i++) { for(unsigned i = 0; i < num_tokens; i++) {
if(cx_cursors[i].kind==CXCursor_DeclRefExpr) { // Temporary fix to a libclang bug if(cx_cursors[i].kind == CXCursor_DeclRefExpr) { // Temporary fix to a libclang bug
auto real_cursor=clang_getCursor(cx_tu, clang_getTokenLocation(cx_tu, cx_tokens[i])); auto real_cursor = clang_getCursor(cx_tu, clang_getTokenLocation(cx_tu, cx_tokens[i]));
cx_cursors[i]=real_cursor; cx_cursors[i] = real_cursor;
} }
// Corrects: when getting tokens from a header, FieldDecl tokens are getting ClassDecl or StructDecl cursors // Corrects: when getting tokens from a header, FieldDecl tokens are getting ClassDecl or StructDecl cursors
else if(!tu_cursors && (cx_cursors[i].kind==CXCursor_ClassDecl || cx_cursors[i].kind==CXCursor_StructDecl)) { else if(!tu_cursors && (cx_cursors[i].kind == CXCursor_ClassDecl || cx_cursors[i].kind == CXCursor_StructDecl)) {
Token token(cx_tu, cx_tokens[i], cx_cursors[i]); Token token(cx_tu, cx_tokens[i], cx_cursors[i]);
auto cursor=token.get_cursor(); auto cursor = token.get_cursor();
auto token_offsets=token.get_source_range().get_offsets(); auto token_offsets = token.get_source_range().get_offsets();
if(token_offsets.second!=cursor.get_source_range().get_offsets().second && token_offsets.first!=cursor.get_source_location().get_offset() && token.is_identifier()) if(token_offsets.second != cursor.get_source_range().get_offsets().second && token_offsets.first != cursor.get_source_location().get_offset() && token.is_identifier())
invalid_tokens.emplace(i, token_offsets.first); invalid_tokens.emplace(i, token_offsets.first);
} }
emplace_back(Token(cx_tu, cx_tokens[i], cx_cursors[i])); emplace_back(Token(cx_tu, cx_tokens[i], cx_cursors[i]));
} }
if(!tu_cursors && !invalid_tokens.empty()) { if(!tu_cursors && !invalid_tokens.empty()) {
@ -50,23 +50,23 @@ clangmm::Tokens::Tokens(CXTranslationUnit &cx_tu, const SourceRange &range, bool
VisitorData data{this, range.get_start().get_path(), invalid_tokens, {}}; VisitorData data{this, range.get_start().get_path(), invalid_tokens, {}};
auto translation_unit_cursor = clang_getTranslationUnitCursor(cx_tu); auto translation_unit_cursor = clang_getTranslationUnitCursor(cx_tu);
clang_visitChildren(translation_unit_cursor, [](CXCursor cx_cursor, CXCursor cx_parent, CXClientData data_) { clang_visitChildren(translation_unit_cursor, [](CXCursor cx_cursor, CXCursor cx_parent, CXClientData data_) {
auto data=static_cast<VisitorData*>(data_); auto data = static_cast<VisitorData *>(data_);
Cursor cursor(cx_cursor); Cursor cursor(cx_cursor);
if(cursor.get_source_location().get_path()==data->path) if(cursor.get_source_location().get_path() == data->path)
data->cursors.emplace_back(cursor); data->cursors.emplace_back(cursor);
return CXChildVisit_Continue; return CXChildVisit_Continue;
}, &data); }, &data);
for(auto &cursor: data.cursors) { for(auto &cursor : data.cursors) {
clang_visitChildren(cursor.cx_cursor, [](CXCursor cx_cursor, CXCursor cx_parent, CXClientData data_) { clang_visitChildren(cursor.cx_cursor, [](CXCursor cx_cursor, CXCursor cx_parent, CXClientData data_) {
auto data=static_cast<VisitorData*>(data_); auto data = static_cast<VisitorData *>(data_);
if(clang_getCursorKind(cx_cursor)==CXCursor_FieldDecl) { if(clang_getCursorKind(cx_cursor) == CXCursor_FieldDecl) {
Cursor cursor(cx_cursor); Cursor cursor(cx_cursor);
auto clang_offset=cursor.get_source_location().get_offset(); auto clang_offset = cursor.get_source_location().get_offset();
for(auto it=data->invalid_tokens.begin();it!=data->invalid_tokens.end();) { for(auto it = data->invalid_tokens.begin(); it != data->invalid_tokens.end();) {
if(it->second==clang_offset) { if(it->second == clang_offset) {
(*data->tokens)[it->first].cx_cursor=cursor.cx_cursor; (*data->tokens)[it->first].cx_cursor = cursor.cx_cursor;
it=data->invalid_tokens.erase(it); it = data->invalid_tokens.erase(it);
if(data->invalid_tokens.empty()) if(data->invalid_tokens.empty())
return CXChildVisit_Break; return CXChildVisit_Break;
break; break;
@ -87,22 +87,22 @@ clangmm::Tokens::~Tokens() {
clang_disposeTokens(cx_tu, cx_tokens, size()); clang_disposeTokens(cx_tu, cx_tokens, size());
} }
//This works across TranslationUnits. Similar tokens defined as tokens with equal canonical cursors. //This works across TranslationUnits. Similar tokens defined as tokens with equal canonical cursors.
std::vector<std::pair<clangmm::Offset, clangmm::Offset> > clangmm::Tokens::get_similar_token_offsets(Cursor::Kind kind, const std::string &spelling, std::vector<std::pair<clangmm::Offset, clangmm::Offset>> clangmm::Tokens::get_similar_token_offsets(Cursor::Kind kind, const std::string &spelling,
const std::unordered_set<std::string> &usrs) { const std::unordered_set<std::string> &usrs) {
std::vector<std::pair<Offset, Offset> > offsets; std::vector<std::pair<Offset, Offset>> offsets;
for(auto &token: *this) { for(auto &token : *this) {
if(token.is_identifier()) { if(token.is_identifier()) {
auto referenced=token.get_cursor().get_referenced(); auto referenced = token.get_cursor().get_referenced();
if(referenced && Cursor::is_similar_kind(referenced.get_kind(), kind)) { if(referenced && Cursor::is_similar_kind(referenced.get_kind(), kind)) {
bool equal_spelling=false; bool equal_spelling = false;
auto cx_string=clang_getTokenSpelling(cx_tu, token.cx_token); auto cx_string = clang_getTokenSpelling(cx_tu, token.cx_token);
if(cx_string.data) if(cx_string.data)
equal_spelling=std::strcmp(static_cast<const char*>(cx_string.data), spelling.c_str())==0; equal_spelling = std::strcmp(static_cast<const char *>(cx_string.data), spelling.c_str()) == 0;
clang_disposeString(cx_string); clang_disposeString(cx_string);
if(equal_spelling) { if(equal_spelling) {
auto referenced_usrs=referenced.get_all_usr_extended(); auto referenced_usrs = referenced.get_all_usr_extended();
for(auto &usr: referenced_usrs) { for(auto &usr : referenced_usrs) {
if(usrs.count(usr)) { if(usrs.count(usr)) {
offsets.emplace_back(token.get_source_range().get_offsets()); offsets.emplace_back(token.get_source_range().get_offsets());
break; break;

18
src/tokens.h

@ -1,25 +1,27 @@
#ifndef TOKENS_H_ #ifndef TOKENS_H_
#define TOKENS_H_ #define TOKENS_H_
#include <clang-c/Index.h>
#include "source_range.h" #include "source_range.h"
#include "token.h" #include "token.h"
#include <clang-c/Index.h>
#include <memory>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
#include <memory>
namespace clangmm { namespace clangmm {
class Tokens : public std::vector<clangmm::Token> { class Tokens : public std::vector<clangmm::Token> {
friend class TranslationUnit; friend class TranslationUnit;
friend class Diagnostic; friend class Diagnostic;
Tokens(CXTranslationUnit &cx_tu, const SourceRange &range, bool annotate_tokens=true); Tokens(CXTranslationUnit &cx_tu, const SourceRange &range, bool annotate_tokens = true);
public: public:
~Tokens(); ~Tokens();
std::vector<std::pair<clangmm::Offset, clangmm::Offset> > get_similar_token_offsets(Cursor::Kind kind, const std::string &spelling, std::vector<std::pair<clangmm::Offset, clangmm::Offset>> get_similar_token_offsets(Cursor::Kind kind, const std::string &spelling,
const std::unordered_set<std::string> &usrs); const std::unordered_set<std::string> &usrs);
private: private:
CXToken *cx_tokens; CXToken *cx_tokens;
std::unique_ptr<CXCursor[]> cx_cursors; std::unique_ptr<CXCursor[]> cx_cursors;
CXTranslationUnit& cx_tu; CXTranslationUnit &cx_tu;
}; };
} // namespace clangmm } // namespace clangmm
#endif // TOKENS_H_ #endif // TOKENS_H_

60
src/translation_unit.cc

@ -5,22 +5,22 @@
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <iostream> //TODO: remove #include <iostream> //TODO: remove
using namespace std; //TODO: remove using namespace std; //TODO: remove
clangmm::TranslationUnit::TranslationUnit(Index &index, const std::string &file_path, clangmm::TranslationUnit::TranslationUnit(Index &index, const std::string &file_path,
const std::vector<std::string> &command_line_args, const std::vector<std::string> &command_line_args,
const std::string &buffer, int flags) { const std::string &buffer, int flags) {
std::vector<const char*> args; std::vector<const char *> args;
for(auto &a: command_line_args) { for(auto &a : command_line_args) {
args.push_back(a.c_str()); args.push_back(a.c_str());
} }
CXUnsavedFile files[1]; CXUnsavedFile files[1];
files[0].Filename=file_path.c_str(); files[0].Filename = file_path.c_str();
files[0].Contents=buffer.c_str(); files[0].Contents = buffer.c_str();
files[0].Length=buffer.size(); files[0].Length = buffer.size();
cx_tu = clang_parseTranslationUnit(index.cx_index, file_path.c_str(), args.data(), cx_tu = clang_parseTranslationUnit(index.cx_index, file_path.c_str(), args.data(),
args.size(), files, 1, flags); args.size(), files, 1, flags);
} }
@ -28,11 +28,11 @@ clangmm::TranslationUnit::TranslationUnit(Index &index, const std::string &file_
clangmm::TranslationUnit::TranslationUnit(Index &index, const std::string &file_path, clangmm::TranslationUnit::TranslationUnit(Index &index, const std::string &file_path,
const std::vector<std::string> &command_line_args, const std::vector<std::string> &command_line_args,
int flags) { int flags) {
std::vector<const char*> args; std::vector<const char *> args;
for(auto &a: command_line_args) { for(auto &a : command_line_args) {
args.push_back(a.c_str()); args.push_back(a.c_str());
} }
cx_tu = clang_parseTranslationUnit(index.cx_index, file_path.c_str(), args.data(), cx_tu = clang_parseTranslationUnit(index.cx_index, file_path.c_str(), args.data(),
args.size(), NULL, 0, flags); args.size(), NULL, 0, flags);
} }
@ -43,39 +43,39 @@ clangmm::TranslationUnit::~TranslationUnit() {
void clangmm::TranslationUnit::parse(Index &index, const std::string &file_path, void clangmm::TranslationUnit::parse(Index &index, const std::string &file_path,
const std::vector<std::string> &command_line_args, const std::vector<std::string> &command_line_args,
const std::map<std::string, std::string> &buffers, int flags) { const std::map<std::string, std::string> &buffers, int flags) {
std::vector<CXUnsavedFile> files; std::vector<CXUnsavedFile> files;
for (auto &buffer : buffers) { for(auto &buffer : buffers) {
CXUnsavedFile file; CXUnsavedFile file;
file.Filename = buffer.first.c_str(); file.Filename = buffer.first.c_str();
file.Contents = buffer.second.c_str(); file.Contents = buffer.second.c_str();
file.Length = buffer.second.size(); file.Length = buffer.second.size();
files.push_back(file); files.push_back(file);
} }
std::vector<const char*> args; std::vector<const char *> args;
for(auto &a: command_line_args) { for(auto &a : command_line_args) {
args.push_back(a.c_str()); args.push_back(a.c_str());
} }
cx_tu = clang_parseTranslationUnit(index.cx_index, file_path.c_str(), args.data(), cx_tu = clang_parseTranslationUnit(index.cx_index, file_path.c_str(), args.data(),
args.size(), files.data(), files.size(), flags); args.size(), files.data(), files.size(), flags);
} }
int clangmm::TranslationUnit::reparse(const std::string &buffer, int flags) { int clangmm::TranslationUnit::reparse(const std::string &buffer, int flags) {
CXUnsavedFile files[1]; CXUnsavedFile files[1];
auto file_path=to_string(clang_getTranslationUnitSpelling(cx_tu)); auto file_path = to_string(clang_getTranslationUnitSpelling(cx_tu));
files[0].Filename=file_path.c_str(); files[0].Filename = file_path.c_str();
files[0].Contents=buffer.c_str(); files[0].Contents = buffer.c_str();
files[0].Length=buffer.size(); files[0].Length = buffer.size();
return clang_reparseTranslationUnit(cx_tu, 1, files, flags); return clang_reparseTranslationUnit(cx_tu, 1, files, flags);
} }
int clangmm::TranslationUnit::DefaultFlags() { int clangmm::TranslationUnit::DefaultFlags() {
int flags=CXTranslationUnit_CacheCompletionResults | CXTranslationUnit_PrecompiledPreamble | CXTranslationUnit_Incomplete | CXTranslationUnit_IncludeBriefCommentsInCodeCompletion; int flags = CXTranslationUnit_CacheCompletionResults | CXTranslationUnit_PrecompiledPreamble | CXTranslationUnit_Incomplete | CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
#if CINDEX_VERSION_MAJOR>0 || (CINDEX_VERSION_MAJOR==0 && CINDEX_VERSION_MINOR>=35) #if CINDEX_VERSION_MAJOR > 0 || (CINDEX_VERSION_MAJOR == 0 && CINDEX_VERSION_MINOR >= 35)
flags|=CXTranslationUnit_KeepGoing; flags |= CXTranslationUnit_KeepGoing;
#endif #endif
return flags; return flags;
} }
@ -88,8 +88,8 @@ clangmm::CodeCompleteResults clangmm::TranslationUnit::get_code_completions(cons
std::vector<clangmm::Diagnostic> clangmm::TranslationUnit::get_diagnostics() { std::vector<clangmm::Diagnostic> clangmm::TranslationUnit::get_diagnostics() {
std::vector<Diagnostic> diagnostics; std::vector<Diagnostic> diagnostics;
for(unsigned c=0;c<clang_getNumDiagnostics(cx_tu);c++) { for(unsigned c = 0; c < clang_getNumDiagnostics(cx_tu); c++) {
CXDiagnostic clang_diagnostic=clang_getDiagnostic(cx_tu, c); CXDiagnostic clang_diagnostic = clang_getDiagnostic(cx_tu, c);
diagnostics.emplace_back(Diagnostic(cx_tu, clang_diagnostic)); diagnostics.emplace_back(Diagnostic(cx_tu, clang_diagnostic));
clang_disposeDiagnostic(clang_diagnostic); clang_disposeDiagnostic(clang_diagnostic);
} }
@ -109,7 +109,7 @@ std::unique_ptr<clangmm::Tokens> clangmm::TranslationUnit::get_tokens(const std:
} }
std::unique_ptr<clangmm::Tokens> clangmm::TranslationUnit::get_tokens(unsigned start_offset, unsigned end_offset) { std::unique_ptr<clangmm::Tokens> clangmm::TranslationUnit::get_tokens(unsigned start_offset, unsigned end_offset) {
auto path=clangmm::to_string(clang_getTranslationUnitSpelling(cx_tu)); auto path = clangmm::to_string(clang_getTranslationUnitSpelling(cx_tu));
SourceLocation start_location(cx_tu, path, start_offset); SourceLocation start_location(cx_tu, path, start_offset);
SourceLocation end_location(cx_tu, path, end_offset); SourceLocation end_location(cx_tu, path, end_offset);
SourceRange range(start_location, end_location); SourceRange range(start_location, end_location);
@ -118,7 +118,7 @@ std::unique_ptr<clangmm::Tokens> clangmm::TranslationUnit::get_tokens(unsigned s
std::unique_ptr<clangmm::Tokens> clangmm::TranslationUnit::get_tokens(unsigned start_line, unsigned start_column, std::unique_ptr<clangmm::Tokens> clangmm::TranslationUnit::get_tokens(unsigned start_line, unsigned start_column,
unsigned end_line, unsigned end_column) { unsigned end_line, unsigned end_column) {
auto path=to_string(clang_getTranslationUnitSpelling(cx_tu)); auto path = to_string(clang_getTranslationUnitSpelling(cx_tu));
SourceLocation start_location(cx_tu, path, start_line, start_column); SourceLocation start_location(cx_tu, path, start_line, start_column);
SourceLocation end_location(cx_tu, path, end_line, end_column); SourceLocation end_location(cx_tu, path, end_line, end_column);
SourceRange range(start_location, end_location); SourceRange range(start_location, end_location);

33
src/translation_unit.h

@ -1,15 +1,15 @@
#ifndef TRANSLATIONUNIT_H_ #ifndef TRANSLATIONUNIT_H_
#define TRANSLATIONUNIT_H_ #define TRANSLATIONUNIT_H_
#include "code_complete_results.h"
#include "cursor.h"
#include "diagnostic.h"
#include "index.h"
#include "tokens.h"
#include <clang-c/Index.h> #include <clang-c/Index.h>
#include <string>
#include <vector>
#include <map> #include <map>
#include <memory> #include <memory>
#include "index.h" #include <string>
#include "diagnostic.h" #include <vector>
#include "tokens.h"
#include "code_complete_results.h"
#include "cursor.h"
namespace clangmm { namespace clangmm {
class TranslationUnit { class TranslationUnit {
@ -17,21 +17,21 @@ namespace clangmm {
TranslationUnit(Index &index, const std::string &file_path, TranslationUnit(Index &index, const std::string &file_path,
const std::vector<std::string> &command_line_args, const std::vector<std::string> &command_line_args,
const std::string &buffer, const std::string &buffer,
int flags=DefaultFlags()); int flags = DefaultFlags());
TranslationUnit(Index &index, const std::string &file_path, TranslationUnit(Index &index, const std::string &file_path,
const std::vector<std::string> &command_line_args, const std::vector<std::string> &command_line_args,
int flags=DefaultFlags()); int flags = DefaultFlags());
~TranslationUnit(); ~TranslationUnit();
int reparse(const std::string &buffer, int flags=DefaultFlags()); int reparse(const std::string &buffer, int flags = DefaultFlags());
static int DefaultFlags(); static int DefaultFlags();
void parse(Index &index, void parse(Index &index,
const std::string &file_path, const std::string &file_path,
const std::vector<std::string> &command_line_args, const std::vector<std::string> &command_line_args,
const std::map<std::string, std::string> &buffers, const std::map<std::string, std::string> &buffers,
int flags=DefaultFlags()); int flags = DefaultFlags());
CodeCompleteResults get_code_completions(const std::string &buffer, CodeCompleteResults get_code_completions(const std::string &buffer,
unsigned line_number, unsigned column); unsigned line_number, unsigned column);
@ -50,6 +50,5 @@ namespace clangmm {
CXTranslationUnit cx_tu; CXTranslationUnit cx_tu;
}; };
} // namespace clangmm } // namespace clangmm
#endif // TRANSLATIONUNIT_H_ #endif // TRANSLATIONUNIT_H_

91
src/utility.cc

@ -3,22 +3,22 @@
std::string clangmm::to_string(CXString cx_string) { std::string clangmm::to_string(CXString cx_string) {
std::string string; std::string string;
if(cx_string.data!=NULL) { if(cx_string.data != NULL) {
string=clang_getCString(cx_string); string = clang_getCString(cx_string);
clang_disposeString(cx_string); clang_disposeString(cx_string);
} }
return string; return string;
} }
clangmm::String::String(const CXString &cx_string) : cx_string(cx_string) { clangmm::String::String(const CXString &cx_string) : cx_string(cx_string) {
if(cx_string.data!=NULL) if(cx_string.data != NULL)
c_str=clang_getCString(cx_string); c_str = clang_getCString(cx_string);
else else
c_str=""; c_str = "";
} }
clangmm::String::~String() { clangmm::String::~String() {
if(cx_string.data!=NULL) if(cx_string.data != NULL)
clang_disposeString(cx_string); clang_disposeString(cx_string);
} }
@ -28,76 +28,77 @@ void clangmm::remove_include_guard(std::string &buffer) {
static std::regex define_regex("^[ \t]*#[ \t]*define[ \t]+([A-Za-z0-9_]+).*$"); static std::regex define_regex("^[ \t]*#[ \t]*define[ \t]+([A-Za-z0-9_]+).*$");
static std::regex endif_regex("^[ \t]*#[ \t]*endif.*$"); static std::regex endif_regex("^[ \t]*#[ \t]*endif.*$");
std::vector<std::pair<size_t, size_t>> ranges; std::vector<std::pair<size_t, size_t>> ranges;
bool found_ifndef=false, found_define=false; bool found_ifndef = false, found_define = false;
bool line_comment=false, multiline_comment=false; bool line_comment = false, multiline_comment = false;
size_t start_of_line=0; size_t start_of_line = 0;
std::string line; std::string line;
std::string preprocessor_identifier; std::string preprocessor_identifier;
for(size_t c=0;c<buffer.size();++c) { for(size_t c = 0; c < buffer.size(); ++c) {
if(!line_comment && !multiline_comment && buffer[c]=='/' && c+1<buffer.size() && (buffer[c+1]=='/' || buffer[c+1]=='*')) { if(!line_comment && !multiline_comment && buffer[c] == '/' && c + 1 < buffer.size() && (buffer[c + 1] == '/' || buffer[c + 1] == '*')) {
if(buffer[c+1]=='/') if(buffer[c + 1] == '/')
line_comment=true; line_comment = true;
else else
multiline_comment=true; multiline_comment = true;
++c; ++c;
} }
else if(multiline_comment && buffer[c]=='*' && c+1<buffer.size() && buffer[c+1]=='/') { else if(multiline_comment && buffer[c] == '*' && c + 1 < buffer.size() && buffer[c + 1] == '/') {
multiline_comment=false; multiline_comment = false;
++c; ++c;
} }
else if(buffer[c]=='\n') { else if(buffer[c] == '\n') {
bool empty_line=true; bool empty_line = true;
for(auto &chr: line) { for(auto &chr : line) {
if(chr!=' ' && chr!='\t') { if(chr != ' ' && chr != '\t') {
empty_line=false; empty_line = false;
break; break;
} }
} }
std::smatch sm; std::smatch sm;
if(empty_line) {} if(empty_line) {
}
else if(!found_ifndef && (std::regex_match(line, sm, ifndef_regex1) || std::regex_match(line, sm, ifndef_regex2))) { else if(!found_ifndef && (std::regex_match(line, sm, ifndef_regex1) || std::regex_match(line, sm, ifndef_regex2))) {
found_ifndef=true; found_ifndef = true;
ranges.emplace_back(start_of_line, c); ranges.emplace_back(start_of_line, c);
preprocessor_identifier=sm[1].str(); preprocessor_identifier = sm[1].str();
} }
else if(found_ifndef && std::regex_match(line, sm, define_regex)) { else if(found_ifndef && std::regex_match(line, sm, define_regex)) {
found_define=true; found_define = true;
ranges.emplace_back(start_of_line, c); ranges.emplace_back(start_of_line, c);
if(preprocessor_identifier!=sm[1].str()) if(preprocessor_identifier != sm[1].str())
return; return;
break; break;
} }
else else
return; return;
line_comment=false; line_comment = false;
line.clear(); line.clear();
if(c+1<buffer.size()) if(c + 1 < buffer.size())
start_of_line=c+1; start_of_line = c + 1;
else else
return; return;
} }
else if(!line_comment && !multiline_comment && buffer[c]!='\r') else if(!line_comment && !multiline_comment && buffer[c] != '\r')
line+=buffer[c]; line += buffer[c];
} }
if(found_ifndef && found_define) { if(found_ifndef && found_define) {
size_t last_char_pos=std::string::npos; size_t last_char_pos = std::string::npos;
for(size_t c=buffer.size()-1;c!=std::string::npos;--c) { for(size_t c = buffer.size() - 1; c != std::string::npos; --c) {
if(last_char_pos==std::string::npos) { if(last_char_pos == std::string::npos) {
if(buffer[c]!=' ' && buffer[c]!='\t' && buffer[c]!='\r' && buffer[c]!='\n') if(buffer[c] != ' ' && buffer[c] != '\t' && buffer[c] != '\r' && buffer[c] != '\n')
last_char_pos=c; last_char_pos = c;
} }
else { else {
if(buffer[c]=='\n' && c+1<buffer.size()) { if(buffer[c] == '\n' && c + 1 < buffer.size()) {
auto line=buffer.substr(c+1, last_char_pos-c); auto line = buffer.substr(c + 1, last_char_pos - c);
std::smatch sm; std::smatch sm;
if(std::regex_match(line, sm, endif_regex)) { if(std::regex_match(line, sm, endif_regex)) {
ranges.emplace_back(c+1, last_char_pos+1); ranges.emplace_back(c + 1, last_char_pos + 1);
for(auto &range: ranges) { for(auto &range : ranges) {
for(size_t c=range.first;c<range.second;++c) { for(size_t c = range.first; c < range.second; ++c) {
if(buffer[c]!='\r') if(buffer[c] != '\r')
buffer[c]=' '; buffer[c] = ' ';
} }
} }
return; return;

8
src/utility.h

@ -5,7 +5,7 @@
namespace clangmm { namespace clangmm {
std::string to_string(CXString cx_string); std::string to_string(CXString cx_string);
class String { class String {
public: public:
String(const CXString &cx_string); String(const CXString &cx_string);
@ -13,8 +13,8 @@ namespace clangmm {
CXString cx_string; CXString cx_string;
const char *c_str; const char *c_str;
}; };
void remove_include_guard(std::string &buffer); void remove_include_guard(std::string &buffer);
} } // namespace clangmm
#endif // UTILITY_H_ #endif // UTILITY_H_

36
tests/code_complete_results_test.cc

@ -1,39 +1,39 @@
#include "clangmm.h" #include "clangmm.h"
#include <string>
#include <cassert> #include <cassert>
#include <regex> #include <regex>
#include <string>
int main() { int main() {
std::string tests_path=LIBCLANGMM_TESTS_PATH; std::string tests_path = LIBCLANGMM_TESTS_PATH;
std::string path(tests_path+"/case/main.cpp"); std::string path(tests_path + "/case/main.cpp");
std::vector<std::string> arguments; std::vector<std::string> arguments;
auto clang_version_string=clangmm::to_string(clang_getClangVersion()); auto clang_version_string = clangmm::to_string(clang_getClangVersion());
const static std::regex clang_version_regex("^[A-Za-z ]+([0-9.]+).*$"); const static std::regex clang_version_regex("^[A-Za-z ]+([0-9.]+).*$");
std::smatch sm; std::smatch sm;
if(std::regex_match(clang_version_string, sm, clang_version_regex)) { if(std::regex_match(clang_version_string, sm, clang_version_regex)) {
auto clang_version=sm[1].str(); auto clang_version = sm[1].str();
arguments.emplace_back("-I/usr/lib/clang/"+clang_version+"/include"); arguments.emplace_back("-I/usr/lib/clang/" + clang_version + "/include");
arguments.emplace_back("-I/usr/lib64/clang/"+clang_version+"/include"); // For Fedora arguments.emplace_back("-I/usr/lib64/clang/" + clang_version + "/include"); // For Fedora
} }
clangmm::Index index(0, 0); clangmm::Index index(0, 0);
clangmm::TranslationUnit tu(index, path, arguments); clangmm::TranslationUnit tu(index, path, arguments);
std::string buffer="#include <string>\n" std::string buffer = "#include <string>\n"
"int main(int argc, char *argv[]) {\n" "int main(int argc, char *argv[]) {\n"
"std::string str;\n" "std::string str;\n"
"str.\n" "str.\n"
"return 0\n" "return 0\n"
"}"; "}";
tu.reparse(buffer); tu.reparse(buffer);
auto results=tu.get_code_completions(buffer, 4, 5); auto results = tu.get_code_completions(buffer, 4, 5);
bool substr_found=false; bool substr_found = false;
for(unsigned c=0;c<results.size();c++) { for(unsigned c = 0; c < results.size(); c++) {
if(results.get(c).get_chunks()[1].text=="substr") { if(results.get(c).get_chunks()[1].text == "substr") {
substr_found=true; substr_found = true;
break; break;
} }
} }

48
tests/completion_string_test.cc

@ -1,46 +1,46 @@
#include "clangmm.h" #include "clangmm.h"
#include <string>
#include <cassert> #include <cassert>
#include <regex> #include <regex>
#include <string>
int main() { int main() {
{ {
clangmm::CompletionChunk str("(", clangmm::CompletionChunk_LeftBrace); clangmm::CompletionChunk str("(", clangmm::CompletionChunk_LeftBrace);
assert(str.text == "("); assert(str.text == "(");
assert(str.kind == clangmm::CompletionChunk_LeftBrace); assert(str.kind == clangmm::CompletionChunk_LeftBrace);
} }
{ {
std::string tests_path=LIBCLANGMM_TESTS_PATH; std::string tests_path = LIBCLANGMM_TESTS_PATH;
std::string path(tests_path+"/case/main.cpp"); std::string path(tests_path + "/case/main.cpp");
std::vector<std::string> arguments; std::vector<std::string> arguments;
auto clang_version_string=clangmm::to_string(clang_getClangVersion()); auto clang_version_string = clangmm::to_string(clang_getClangVersion());
const static std::regex clang_version_regex("^[A-Za-z ]+([0-9.]+).*$"); const static std::regex clang_version_regex("^[A-Za-z ]+([0-9.]+).*$");
std::smatch sm; std::smatch sm;
if(std::regex_match(clang_version_string, sm, clang_version_regex)) { if(std::regex_match(clang_version_string, sm, clang_version_regex)) {
auto clang_version=sm[1].str(); auto clang_version = sm[1].str();
arguments.emplace_back("-I/usr/lib/clang/"+clang_version+"/include"); arguments.emplace_back("-I/usr/lib/clang/" + clang_version + "/include");
arguments.emplace_back("-I/usr/lib64/clang/"+clang_version+"/include"); // For Fedora arguments.emplace_back("-I/usr/lib64/clang/" + clang_version + "/include"); // For Fedora
} }
clangmm::Index index(0, 0); clangmm::Index index(0, 0);
clangmm::TranslationUnit tu(index, path, arguments); clangmm::TranslationUnit tu(index, path, arguments);
std::string buffer="#include <string>\n" std::string buffer = "#include <string>\n"
"int main(int argc, char *argv[]) {\n" "int main(int argc, char *argv[]) {\n"
"std::string str;\n" "std::string str;\n"
"str.\n" "str.\n"
"return 0\n" "return 0\n"
"}"; "}";
tu.reparse(buffer); tu.reparse(buffer);
auto results=tu.get_code_completions(buffer, 4, 5); auto results = tu.get_code_completions(buffer, 4, 5);
auto str = results.get(0); auto str = results.get(0);
assert(str.get_num_chunks()>0); assert(str.get_num_chunks() > 0);
assert(str.get_chunks().size()>0); assert(str.get_chunks().size() > 0);
} }
} }

20
tests/cursor_test.cc

@ -1,27 +1,27 @@
#include "clangmm.h" #include "clangmm.h"
#include <string>
#include <cassert> #include <cassert>
#include <regex> #include <regex>
#include <string>
int main() { int main() {
std::string tests_path=LIBCLANGMM_TESTS_PATH; std::string tests_path = LIBCLANGMM_TESTS_PATH;
std::string path(tests_path+"/case/main.cpp"); std::string path(tests_path + "/case/main.cpp");
clangmm::Index index(0, 0); clangmm::Index index(0, 0);
std::vector<std::string> arguments; std::vector<std::string> arguments;
auto clang_version_string=clangmm::to_string(clang_getClangVersion()); auto clang_version_string = clangmm::to_string(clang_getClangVersion());
const static std::regex clang_version_regex("^[A-Za-z ]+([0-9.]+).*$"); const static std::regex clang_version_regex("^[A-Za-z ]+([0-9.]+).*$");
std::smatch sm; std::smatch sm;
if(std::regex_match(clang_version_string, sm, clang_version_regex)) { if(std::regex_match(clang_version_string, sm, clang_version_regex)) {
auto clang_version=sm[1].str(); auto clang_version = sm[1].str();
arguments.emplace_back("-I/usr/lib/clang/"+clang_version+"/include"); arguments.emplace_back("-I/usr/lib/clang/" + clang_version + "/include");
arguments.emplace_back("-I/usr/lib64/clang/"+clang_version+"/include"); // For Fedora arguments.emplace_back("-I/usr/lib64/clang/" + clang_version + "/include"); // For Fedora
} }
clangmm::TranslationUnit tu(index, path, arguments); clangmm::TranslationUnit tu(index, path, arguments);
auto cursor=tu.get_cursor(path, 103); auto cursor = tu.get_cursor(path, 103);
assert(cursor.get_kind() == clangmm::Cursor::Kind::ReturnStmt); assert(cursor.get_kind() == clangmm::Cursor::Kind::ReturnStmt);
} }

24
tests/diagnostics_test.cc

@ -1,31 +1,31 @@
#include "clangmm.h" #include "clangmm.h"
#include <iostream>
#include <fstream>
#include <cassert> #include <cassert>
#include <fstream>
#include <iostream>
#include <regex> #include <regex>
using namespace std; using namespace std;
int main() { int main() {
std::string tests_path=LIBCLANGMM_TESTS_PATH; std::string tests_path = LIBCLANGMM_TESTS_PATH;
std::string path(tests_path+"/case/main_error.cpp"); std::string path(tests_path + "/case/main_error.cpp");
clangmm::Index index(0, 0); clangmm::Index index(0, 0);
std::vector<std::string> arguments; std::vector<std::string> arguments;
auto clang_version_string=clangmm::to_string(clang_getClangVersion()); auto clang_version_string = clangmm::to_string(clang_getClangVersion());
const static std::regex clang_version_regex("^[A-Za-z ]+([0-9.]+).*$"); const static std::regex clang_version_regex("^[A-Za-z ]+([0-9.]+).*$");
std::smatch sm; std::smatch sm;
if(std::regex_match(clang_version_string, sm, clang_version_regex)) { if(std::regex_match(clang_version_string, sm, clang_version_regex)) {
auto clang_version=sm[1].str(); auto clang_version = sm[1].str();
arguments.emplace_back("-I/usr/lib/clang/"+clang_version+"/include"); arguments.emplace_back("-I/usr/lib/clang/" + clang_version + "/include");
arguments.emplace_back("-I/usr/lib64/clang/"+clang_version+"/include"); // For Fedora arguments.emplace_back("-I/usr/lib64/clang/" + clang_version + "/include"); // For Fedora
} }
clangmm::TranslationUnit tu(index, path, arguments); clangmm::TranslationUnit tu(index, path, arguments);
auto diagnostics=tu.get_diagnostics(); auto diagnostics = tu.get_diagnostics();
assert(diagnostics.size()>0); assert(diagnostics.size() > 0);
assert(!diagnostics[0].spelling.empty()); assert(!diagnostics[0].spelling.empty());
assert(diagnostics[0].severity==clangmm::Diagnostic::Severity::Error); assert(diagnostics[0].severity == clangmm::Diagnostic::Severity::Error);
} }

12
tests/source_location_test.cc

@ -1,18 +1,18 @@
#include "clangmm.h" #include "clangmm.h"
#include <string>
#include <cassert> #include <cassert>
#include <string>
int main() { int main() {
std::string tests_path=LIBCLANGMM_TESTS_PATH; std::string tests_path = LIBCLANGMM_TESTS_PATH;
std::string path(tests_path+"/case/main.cpp"); std::string path(tests_path + "/case/main.cpp");
clangmm::Index index(0, 0); clangmm::Index index(0, 0);
clangmm::TranslationUnit tu(index, path, {}); clangmm::TranslationUnit tu(index, path, {});
auto tokens=tu.get_tokens(0, 113); auto tokens = tu.get_tokens(0, 113);
auto offsets = (*tokens)[28].get_source_range().get_offsets();
auto offsets=(*tokens)[28].get_source_range().get_offsets();
assert(offsets.first.line == 6 && offsets.first.index == 3); assert(offsets.first.line == 6 && offsets.first.index == 3);
assert(offsets.second.line == 6 && offsets.second.index == 9); assert(offsets.second.line == 6 && offsets.second.index == 9);
} }

12
tests/token_test.cc

@ -1,20 +1,20 @@
#include "clangmm.h" #include "clangmm.h"
#include <string>
#include <cassert> #include <cassert>
#include <string>
int main() { int main() {
std::string tests_path=LIBCLANGMM_TESTS_PATH; std::string tests_path = LIBCLANGMM_TESTS_PATH;
std::string path(tests_path+"/case/main.cpp"); std::string path(tests_path + "/case/main.cpp");
clangmm::Index index(0, 0); clangmm::Index index(0, 0);
clangmm::TranslationUnit tu(index, path, {}); clangmm::TranslationUnit tu(index, path, {});
auto tokens=tu.get_tokens(0, 113); auto tokens = tu.get_tokens(0, 113);
assert(tokens->size() == 32); assert(tokens->size() == 32);
assert((*tokens)[1].get_kind() == clangmm::Token::Kind::Identifier); assert((*tokens)[1].get_kind() == clangmm::Token::Kind::Identifier);
std::string str = (*tokens)[28].get_spelling(); std::string str = (*tokens)[28].get_spelling();
assert(str == "return"); assert(str == "return");
} }

10
tests/translation_unit_test.cc

@ -1,14 +1,14 @@
#include "clangmm.h" #include "clangmm.h"
#include <string>
#include <map>
#include <cassert> #include <cassert>
#include <map>
#include <string>
int main() { int main() {
std::string tests_path=LIBCLANGMM_TESTS_PATH; std::string tests_path = LIBCLANGMM_TESTS_PATH;
std::string path(tests_path+"/case/main.cpp"); std::string path(tests_path + "/case/main.cpp");
clangmm::Index index(0, 0); clangmm::Index index(0, 0);
clangmm::TranslationUnit tu(index, path, {}); clangmm::TranslationUnit tu(index, path, {});
std::string buffer = "int main(int argc, char *argv[]) {\n" std::string buffer = "int main(int argc, char *argv[]) {\n"

Loading…
Cancel
Save