16 Commits
Author SHA1 Message Date
Malte LangkabelandGitHub 49e8458d6d Merge pull request #6 from CoatiSoftware/ambiguous_references
add methods to record edges as ambiguous
2019-05-20 11:50:14 +02:00
mlangkabel f78a7186c1 add methods to record edges as ambiguous 2019-05-06 17:22:20 +02:00
mlangkabel f14a8a0a19 fetch version number from file instead of using git tag
This allows users to download the repository as zip. Furthermore this change also allows the user to increase the version number in the working tree, without having to commit and tag.
2019-05-01 16:34:55 +02:00
mlangkabel 2dad29877f expose getVersionString() in API 2019-04-02 17:52:58 +02:00
Malte LangkabelandGitHub 02647c418c Merge pull request #5 from CoatiSoftware/record_qualifier_location
Record qualifier locations
2019-03-26 12:04:01 +01:00
mlangkabel 5dd33e9ecf extend cpp api example to record a qualifier location 2019-03-26 11:33:20 +01:00
mlangkabel 6a55b81e33 add test 2019-03-26 11:33:12 +01:00
mlangkabel 24668448f5 implement functionality to store a qualifier location to the database 2019-03-26 11:33:01 +01:00
Malte LangkabelandGitHub 702330265f Merge pull request #4 from CoatiSoftware/fix_examples
Fix examples for windows
2019-03-26 11:20:19 +01:00
mlangkabel 52635f23f3 fix the same errors in python api example 2019-03-26 11:08:22 +01:00
mlangkabel c4aad954e2 fix some logic and functional errors in the cpp api example 2019-03-26 11:08:14 +01:00
mlangkabel 3b76c403dc rename recordCommentLocation to recordAtomicSourceRange
This is done because the feature can be useful for all kind of multi-line symbols that should not be split being part of a code snippet.
2019-02-26 17:12:18 +01:00
mlangkabel b8664ce131 add Language Extension Guide 2019-02-26 15:36:12 +01:00
mlangkabel 495b40ef16 extend readme with information on relevance of the repo's tags 2019-02-01 16:29:30 +01:00
mlangkabel 4edb7f26ac fix build issue if tags of this repo are not checked out (issue #1) 2019-02-01 15:43:16 +01:00
Eberhard Graether db936766e4 added C++ Poetry Indexer image to README introduction 2018-12-19 15:37:21 +01:00
23 changed files with 524 additions and 63 deletions
+2 -1
View File
@@ -111,7 +111,8 @@ before_deploy:
- |
cd $TRAVIS_BUILD_DIR
VERSION=$(head -1 build/version.txt)
VERSION=$(head -1 version.txt)
VERSION=${VERSION//./_}
if [[ "$PYTHON_BINDING" == "1" ]]; then
PYTHON_VERSION=${PYTHON//.}
+4 -21
View File
@@ -22,23 +22,11 @@ endif()
# --- Version ---
if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
find_package(Git)
file (STRINGS "version.txt" VERSION_STRING)
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --long
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_VERSION_NUMBER
OUTPUT_STRIP_TRAILING_WHITESPACE
)
else()
set(GIT_VERSION_NUMBER "v0.db0.p0-0-a")
endif()
string(REGEX REPLACE "v([0-9]+)\\..*" "\\1" INTERFACE_VERSION "${GIT_VERSION_NUMBER}")
string(REGEX REPLACE "v[0-9]+\\.db([0-9]+)\\..*" "\\1" DATABASE_VERSION "${GIT_VERSION_NUMBER}")
string(REGEX REPLACE "v[0-9]+\\.db[0-9]+\\.p([0-9]+)-.*" "\\1" PATCH_VERSION "${GIT_VERSION_NUMBER}")
set(VERSION_STRING "v${INTERFACE_VERSION}.db${DATABASE_VERSION}.p${PATCH_VERSION}")
string(REGEX REPLACE "v([0-9]+)\\..*" "\\1" INTERFACE_VERSION "${VERSION_STRING}")
string(REGEX REPLACE "v[0-9]+\\.db([0-9]+)\\..*" "\\1" DATABASE_VERSION "${VERSION_STRING}")
string(REGEX REPLACE "v[0-9]+\\.db[0-9]+\\.p([0-9]+).*" "\\1" PATCH_VERSION "${VERSION_STRING}")
set(VERSION_STRING_UNDERSCORE "v${INTERFACE_VERSION}_db${DATABASE_VERSION}_p${PATCH_VERSION}")
message(STATUS "SourcetrailDB Version: ${VERSION_STRING}")
@@ -46,11 +34,6 @@ message(STATUS "Interface Version: ${INTERFACE_VERSION}")
message(STATUS "Database Version: ${DATABASE_VERSION}")
message(STATUS "Patch Version: ${PATCH_VERSION}")
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/version.txt.in
"${CMAKE_CURRENT_BINARY_DIR}/version.txt"
)
# --- Core ---
+56
View File
@@ -0,0 +1,56 @@
# Sourcetrail Language Extension Guide
## First Things First
Build on the shoulders of giants. There are many language tools and frameworks out there that you can build upon, helping you to get things done much faster:
Look for a parser that generates an Abstract Syntax Tree (AST) for the language you want to index. The parser can be written in any language, but for parsing programming languages these tools are mostly written in the language they are designed to parse. You will probably use the generated AST to visit certain nodes (e.g. all `function definition` nodes) and store all the useful information to the Sourcetrail database (e.g. a `function` with name `foo` is defined at location `<X:Y>`).
Having a parser is fine, but it is not enough. When you parse code that contains a function call, the parser may just create a `call expression` node for you. You may even be able to get the name of the called function from the AST node, but the parser certainly will not know where this function is actually defined. And if the indexed code defines two or more functions with the same name, you are in trouble.
That's why it`s best to have a framework that can resolve this info for you. Just to name a few examples:
* for Java there is the [JavaParser](https://github.com/javaparser/javaparser) for building the AST and the [JavaSymbolSolver](https://github.com/javaparser/javasymbolsolver) (now integrated into JavaParser) for resolving these references.
* for C/C++ this is all done by the [Clang](https://clang.llvm.org/) compiler frontend.
* for Python the AST can be built by [parso](https://github.com/davidhalter/parso) while the references can be solved by [Jedi](https://github.com/davidhalter/jedi).
## Getting Started
Ok, let's assume that you found some awesome frameworks that help you build your Sourcetrail Language Package. So what's next?
1. Start off by writing a small executable piece of code that reads in some input code and generates the AST. For the scope of this guide, let's assume that the following piece of Python code would be your snippet.
<!-- language: python -->
class Foo:
def bar():
return 0
f = Foo()
f.bar()
2. Implement an AST visitor that visits each node of the generated AST and prints that node's type. This functionality will come in handy for debugging your code later on. For our piece of sample code, the AST may look like this:
<!-- language: language-none -->
file_input
|-classdef [Foo]
| `-funcdef [bar()]
| `-return
| `-number [0]
|-assignment
| |-name [f]
| `-call
| `-name [Foo()]
|-call
| `-name [bar()]
| `-qualifier [f]
`-endmarker
3. Make the [SourcetrailDB interface](https://github.com/CoatiSoftware/SourcetrailDB#sourcetraildb-api) accessible from your code base. You can either use [existing bindings](https://github.com/CoatiSoftware/SourcetrailDB#supported-language-bindings) for your desired language or open an issue at the [SourcetrailDB issues page](https://github.com/CoatiSoftware/SourcetrailDB/issues). If your language package has made it to this stage, the SourcetrailDB team will be happy to support your project!
4. Use SourcetrailDB from within your code base by opening a `.srctrldb` file before traversing your AST and closing it again after the AST visitor is done.
5. Your AST should already have information available on where certain symbols are defined (e.g. `classdef [Foo]` and `funcdef [bar()]`). Try to extend your AST visitor to store this information to the Sourcetrail Database (e.g. whenever you visit a class or function declaration, try to create a node with the symbol's name (e.g. `Foo` and `Foo.bar`) in the Sourcetrail database).
6. Setup an automated test suite that runs test cases for indexing code snippets with syntax you already covered in your language package. This way you can make sure that you don`t break things as you move forward.
7. Extend your AST visitor to store additional information for the symbols that you already record (e.g. symbol kind, definition kind, source location).
8. Record references between your symbols. Now, this is the tricky part. Within your AST you may encounter a node that describe references to other nodes (e.g. `call`). Use your language processing framework to resolve those references. For our example this language processing framework would need to find out that
* `bar()` is called on the object in variable `f` and
* `f` contains an instance of the class `Foo` so
* `f.bar()` actually describes a call to `Foo.bar()`.
9. If you have made it this far: Congratulations! You already have a solid Sourcetrail language package up and running! It is time to get your language package linked in the [SourcetrailDB Readme](https://github.com/CoatiSoftware/SourcetrailDB#projects-using-sourcetraildb). Just open an issue or create a pull request.
10. Now it's just about extending the package to record more and more stuff and cover the remaining edge cases. Once the package is mature, it may be integrated and shipped with the official Sourcetrail releases, if you agree and if your licensing terms allow.
+5
View File
@@ -13,8 +13,11 @@ Linux and macOS: [![Build Status](https://travis-ci.org/CoatiSoftware/Sourcetrai
The SourcetrailDB project provides write access to [Sourcetrail](https://www.sourcetrail.com/) database files. You can use the SourcetrailDB project to write an indexer for an arbitrary programming language (or other kind of data, e.g. see [poetry indexer example](examples/cpp_poetry_indexer)) and export a Sourcetrail database file that can be viewed and navigated within Sourcetrail.
!["C++ Poetry Indexer"](images/readme/00_cpp_poetry_indexer.png "C++ Poetry Indexer")
## Projects Using SourcetrailDB
The following list of projects already use SourcetrailDB API to extend the language support of Sourcetrail. If you plan on starting a language package on your own, take a look at our [Language Extension Guide](LANGUAGE_EXTENSION_GUIDE.md).
* [SourcetrailPythonIndexer](https://github.com/CoatiSoftware/SourcetrailPythonIndexer)
@@ -43,6 +46,8 @@ Take a look at [Appveyor (for Windows)](appveyor.yml) or [Travis (for Linux and
### SourcetrailDB Core
Before building the core project, please make sure that you also have checked out the tags of this repository (they are relevant for deriving version number information during the build).
Requirements:
* [CMake](https://cmake.org/) >= 2.6
* C++-Compiler with C++11 support
+5 -4
View File
@@ -69,9 +69,10 @@ before_build:
- cd build
- cmake -G "%CMAKE_GENERATOR%" ../ -DBUILD_BINDINGS_PYTHON=ON -DPYTHON_LIBRARY="%PYTHON_PATH%/libs/python%PYTHON_VERSION%.lib"
- cd ../
- ps: $env:CORE_VERSION = Get-Content -Path ./build/version.txt
- ps: $env:CORE_VERSION = Get-Content -Path ./version.txt
- ps: $env:UNDERSCORED_CORE_VERSION = $env:CORE_VERSION.Replace(".", "_")
- ps: echo "Core version is $env:CORE_VERSION"
# TODO: convert the core version into dotted format and update appveyor version here
# TODO: use the core version to update appveyor version here
# - ps: $env:BUILD_VERSION = "0.0.1." + $env:APPVEYOR_BUILD_NUMBER
# - ps: echo update build version to $env:BUILD_VERSION
# - ps: Update-AppveyorBuild -Version $env:BUILD_VERSION
@@ -84,8 +85,8 @@ build_script:
after_build:
- ps: $env:CORE_PACKAGE_NAME = 'sourcetraildb_core_' + $env:CORE_VERSION + '-windows-' + $env:MBITS + 'bit-msvc' + $env:MSVC_VERSION
- ps: $env:PYTHON_PACKAGE_NAME = 'sourcetrailbd_python' + $env:PYTHON_VERSION + '_' + $env:CORE_VERSION + '-windows-' + $env:MBITS + 'bit'
- ps: $env:CORE_PACKAGE_NAME = 'sourcetraildb_core_' + $env:UNDERSCORED_CORE_VERSION + '-windows-' + $env:MBITS + 'bit-msvc' + $env:MSVC_VERSION
- ps: $env:PYTHON_PACKAGE_NAME = 'sourcetrailbd_python' + $env:PYTHON_VERSION + '_' + $env:UNDERSCORED_CORE_VERSION + '-windows-' + $env:MBITS + 'bit'
- ps: echo $env:CORE_PACKAGE_NAME
- ps: echo $env:PYTHON_PACKAGE_NAME
- mkdir artifacts_core
+3
View File
@@ -16,6 +16,7 @@ set(LIB_SRC_FILES
src/DatabaseStorage.cpp
src/DefinitionKind.cpp
src/EdgeKind.cpp
src/ElementComponentKind.cpp
src/LocationKind.cpp
src/NameHierarchy.cpp
src/NodeKind.cpp
@@ -32,6 +33,7 @@ set(LIB_HDR_FILES
include/DatabaseStorage.h
include/DefinitionKind.h
include/EdgeKind.h
include/ElementComponentKind.h
include/LocationKind.h
include/NameHierarchy.h
include/NodeKind.h
@@ -40,6 +42,7 @@ set(LIB_HDR_FILES
include/SourcetrailDBWriter.h
include/SourcetrailException.h
include/StorageEdge.h
include/StorageElementComponent.h
include/StorageError.h
include/StorageFile.h
include/StorageLocalSymbol.h
+3
View File
@@ -24,6 +24,7 @@
#include "CppSQLite3.h"
#include "StorageEdge.h"
#include "StorageElementComponent.h"
#include "StorageError.h"
#include "StorageFile.h"
#include "StorageLocalSymbol.h"
@@ -61,6 +62,7 @@ namespace sourcetrail
void rollbackTransaction();
void optimizeDatabaseMemory();
int addElementComponent(const StorageElementComponentData& storageElementComponentData);
int addNode(const StorageNodeData& storageNodeData);
void addSymbol(const StorageSymbol& storageSymbol);
void addFile(const StorageFile& storageFile);
@@ -102,6 +104,7 @@ namespace sourcetrail
mutable CppSQLite3DB m_database;
CppSQLite3Statement m_insertElementStatement;
CppSQLite3Statement m_insertElementComponentStatement;
CppSQLite3Statement m_findNodeStatement;
CppSQLite3Statement m_insertNodeStatement;
CppSQLite3Statement m_setNodeTypeStmt;
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_ELEMENT_COMPONENT_KIND_H
#define SOURCETRAIL_ELEMENT_COMPONENT_KIND_H
namespace sourcetrail
{
/**
* Enum providing all possible values for kinds of node and edge components that can be stored to the Sourcetrail database.
*/
enum class ElementComponentKind : int
{
IS_AMBIGUOUS = 1 << 0
};
int elementComponentKindToInt(ElementComponentKind kind);
ElementComponentKind intToElementComponentKind(int i);
}
#endif // SOURCETRAIL_ELEMENT_COMPONENT_KIND_H
+3 -2
View File
@@ -29,10 +29,11 @@ namespace sourcetrail
QUALIFIER = 2,
LOCAL_SYMBOL = 3,
SIGNATURE = 4,
COMMENT = 5,
ATOMIC_RANGE = 5,
INDEXER_ERROR = 6,
FULLTEXT_SEARCH = 7,
SCREEN_SEARCH = 8
SCREEN_SEARCH = 8,
UNSOLVED = 9
};
int locationKindToInt(LocationKind kind);
+66 -5
View File
@@ -22,6 +22,7 @@
#include "DefinitionKind.h"
#include "EdgeKind.h"
#include "ElementComponentKind.h"
#include "LocationKind.h"
#include "NameHierarchy.h"
#include "ReferenceKind.h"
@@ -349,6 +350,62 @@ namespace sourcetrail
*/
bool recordReferenceLocation(int referenceId, const SourceRange& location);
/**
* Marks a reference that is stored in the database as "ambiguous"
*
* This method allows to additional information for a reference to the database. Sourcetrail will
* display an "ambiguous" reference with a special style to emphasize that the existance of the
* reference is questionable. This method is intended to be called in situations when an indexed
* token may have meanings, all of which shall be recorded.
*
* param: referenceId - the id of the reference that shall be marked as ambiguous.
*
* return: true if successful. false on failure. getLastError() provides the error message.
*/
bool recordReferenceIsAmbiuous(int referenceId);
/**
* Stores a location between a specific context and an "unsolved" symbol to the database
*
* This method allows to store all available information to the database in the case that a symbol
* is referenced in a certain context but the referenced symbol could not be resolved to a concrete
* name. For each reference recorded by this method, Sourcetrail's graph view will display an edge
* that originates at the recorded context symbol and points to a node called "unsolved symbol".
* Furthermore Sourcetrail's code view will use a different highlight when the provided source range
* gets hovered.
*
* param: contextSymbolId - the id of the source of the recorded reference edge
* param: referenceKind - kind of the recorded reference edge
* param: location - the SourceRange that shall be recorded as location for the respective
* reference.
*
* return: referenceId - integer id of the stored reference. 0 on failure. getLastError()
* provides the error message.
*
* see: SourceRange
*/
int recordReferenceToUnsolvedSymhol(int contextSymbolId, ReferenceKind referenceKind, const SourceRange& location);
/**
* Stores a location for the usage of a symbol's name as qualifier to the database
*
* This method allows to store a location where a specific symbol is used as a qualifier to the
* database. Calling this method with the same referencedSymbolId multiple times adds multiple locations
* for the respective reference. The stored location will be clickable but not displayable: When the
* reference location is clicked Sourcetrail will activate the symbol referenced by the respective
* reference. When the symbol with the specified id is activated, this location will NOT be displayed and
* highlighted by Sourcetrail.
*
* param: referencedSymbolId - the id of the symbol that is used as qualifier at the current location.
* param: location - the SourceRange that shall be recorded as location for the symbol's occurrence as
* qualifier
*
* return: true if successful. false on failure. getLastError() provides the error message.
*
* see: SourceRange
*/
bool recordQualifierLocation(int referencedSymbolId, const SourceRange& location);
/**
* Stores a file to the database
*
@@ -411,18 +468,21 @@ namespace sourcetrail
bool recordLocalSymbolLocation(int localSymbolId, const SourceRange& location);
/**
* Stores a comment location to the database
* Stores an atomic SourceRange to the database
*
* This method allows to store a comment location to the database. These comment locations will
* be used by Sourcetrail to prevent the code view from displaying comments imcomplete.
* This method allows to store an atomic SourceRange to the database. These ranges will
* be used by Sourcetrail to prevent the code view from displaying only a part of the range. Thus,
* if any line that lies within one of the project's atomic ranges is dispayed, the remaining
* lines will be displayed as well. This may be useful for dealing with multi-line comments or
* multi-line strings.
*
* param: location - the SourceRange of the comment to record.
* param: sourceRange - the SourceRange to record.
*
* return: true if successful. false on failure. getLastError() provides the error message.
*
* see: SourceRange
*/
bool recordCommentLocation(const SourceRange& location);
bool recordAtomicSourceRange(const SourceRange& sourceRange);
/**
* Stores an indexing error to the database
@@ -452,6 +512,7 @@ namespace sourcetrail
int addFile(const std::string& filePath);
int addEdge(int sourceId, int targetId, EdgeKind edgeKind);
void addSourceLocation(int elementId, const SourceRange& location, LocationKind kind);
void addElementComponent(int elementId, ElementComponentKind kind, const std::string& data);
std::string m_projectFilePath;
std::string m_databaseFilePath;
+64
View File
@@ -0,0 +1,64 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SOURCETRAIL_STORAGE_ELEMENT_COMPONENT_H
#define SOURCETRAIL_STORAGE_ELEMENT_COMPONENT_H
#include <string>
namespace sourcetrail
{
struct StorageElementComponentData
{
StorageElementComponentData()
: elementId(0)
, componentKind(0)
, data("")
{}
StorageElementComponentData(int elementId, int componentKind, std::string data)
: elementId(elementId)
, componentKind(componentKind)
, data(std::move(data))
{}
int elementId;
int componentKind;
std::string data;
};
struct StorageElementComponent : public StorageElementComponentData
{
StorageElementComponent()
: StorageElementComponentData()
, id(0)
{}
StorageElementComponent(int id, const StorageElementComponentData& data)
: StorageElementComponentData(data)
, id(id)
{}
StorageElementComponent(int id, int elementId, int componentKind, std::string data)
: StorageElementComponentData(elementId, componentKind, data)
, id(id)
{}
int id;
};
}
#endif // SOURCETRAIL_STORAGE_ELEMENT_COMPONENT_H
+28
View File
@@ -151,6 +151,17 @@ namespace sourcetrail
executeStatement("VACUUM;");
}
int DatabaseStorage::addElementComponent(const StorageElementComponentData& storageElementComponentData)
{
m_insertElementComponentStatement.bind(1, storageElementComponentData.elementId);
m_insertElementComponentStatement.bind(2, storageElementComponentData.componentKind);
m_insertElementComponentStatement.bind(3, storageElementComponentData.data.c_str());
executeStatement(m_insertElementComponentStatement);
int id = m_database.lastRowId();
m_insertElementComponentStatement.reset();
return id;
}
int DatabaseStorage::addNode(const StorageNodeData& storageNodeData)
{
int id = 0;
@@ -393,6 +404,17 @@ namespace sourcetrail
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS element_component("
" id INTEGER, "
" element_id INTEGER, "
" type INTEGER, "
" data TEXT, "
" PRIMARY KEY(id), "
" FOREIGN KEY(element_id) REFERENCES element(id) ON DELETE CASCADE"
");"
);
executeStatement(
"CREATE TABLE IF NOT EXISTS edge("
" id INTEGER NOT NULL, "
@@ -518,6 +540,7 @@ namespace sourcetrail
"symbol",
"node",
"edge",
"element_component"
"element"
};
@@ -557,6 +580,10 @@ namespace sourcetrail
"INSERT INTO element(id) VALUES(NULL);"
);
m_insertElementComponentStatement = compileStatement(
"INSERT INTO element_component(id, element_id, type, data) VALUES(NULL, ?, ?, ?);"
);
m_findNodeStatement = compileStatement(
"SELECT id FROM node WHERE serialized_name == ? LIMIT 1;"
);
@@ -648,6 +675,7 @@ namespace sourcetrail
void DatabaseStorage::clearPrecompiledStatements()
{
m_insertElementStatement.finalize();
m_insertElementComponentStatement.finalize();
m_findNodeStatement.finalize();
m_insertNodeStatement.finalize();
m_setNodeTypeStmt.finalize();
+44
View File
@@ -0,0 +1,44 @@
/*
* Copyright 2018 Coati Software KG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ElementComponentKind.h"
#include "SourcetrailException.h"
namespace sourcetrail
{
int elementComponentKindToInt(ElementComponentKind kind)
{
return static_cast<int>(kind);
}
ElementComponentKind intToElementComponentKind(int i)
{
const ElementComponentKind kinds[] = {
ElementComponentKind::IS_AMBIGUOUS
};
for (ElementComponentKind kind : kinds)
{
if (i == elementComponentKindToInt(kind))
{
return kind;
}
}
throw SourcetrailException("Unable to convert integer \"" + std::to_string(i) + "\" to element component kind.");
}
}
+3 -2
View File
@@ -33,10 +33,11 @@ namespace sourcetrail
LocationKind::QUALIFIER,
LocationKind::LOCAL_SYMBOL,
LocationKind::SIGNATURE,
LocationKind::COMMENT,
LocationKind::ATOMIC_RANGE,
LocationKind::INDEXER_ERROR,
LocationKind::FULLTEXT_SEARCH,
LocationKind::SCREEN_SEARCH
LocationKind::SCREEN_SEARCH,
LocationKind::UNSOLVED
};
for (LocationKind kind : kinds)
+85 -10
View File
@@ -428,7 +428,7 @@ namespace sourcetrail
if (!m_storage)
{
m_lastError = "Unable to record reference, because no database is currently open.";
return false;
return 0;
}
try
@@ -446,7 +446,7 @@ namespace sourcetrail
{
if (!m_storage)
{
m_lastError = "Unable to record symbol signature location, because no database is currently open.";
m_lastError = "Unable to record symbol reference location, because no database is currently open.";
return false;
}
@@ -462,6 +462,72 @@ namespace sourcetrail
}
}
bool SourcetrailDBWriter::recordReferenceIsAmbiuous(int referenceId)
{
if (!m_storage)
{
m_lastError = "Unable to record ambiguity of reference, because no database is currently open.";
return false;
}
try
{
addElementComponent(referenceId, ElementComponentKind::IS_AMBIGUOUS, "");
return false;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
int SourcetrailDBWriter::recordReferenceToUnsolvedSymhol(int contextSymbolId, ReferenceKind referenceKind, const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol reference, because no database is currently open.";
return 0;
}
try
{
NameHierarchy unsolvedSymbolName;
NameElement unsolvedSymbolNameElement;
unsolvedSymbolNameElement.name = "unsolved symbol";
unsolvedSymbolName.nameElements.push_back(unsolvedSymbolNameElement);
int unsolvedSymbolId = addNodeHierarchy(unsolvedSymbolName);
int referenceId = addEdge(contextSymbolId, unsolvedSymbolId, referenceKindToEdgeKind(referenceKind));
addSourceLocation(referenceId, location, LocationKind::UNSOLVED);
return referenceId;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return 0;
}
}
bool SourcetrailDBWriter::recordQualifierLocation(int referencedSymbolId, const SourceRange& location)
{
if (!m_storage)
{
m_lastError = "Unable to record symbol qualifier location, because no database is currently open.";
return false;
}
try
{
addSourceLocation(referencedSymbolId, location, LocationKind::QUALIFIER);
return true;
}
catch (const SourcetrailException e)
{
m_lastError = e.getMessage();
return false;
}
}
int SourcetrailDBWriter::recordFile(const std::string& filePath)
{
if (!m_storage)
@@ -541,23 +607,23 @@ namespace sourcetrail
}
}
bool SourcetrailDBWriter::recordCommentLocation(const SourceRange& location)
bool SourcetrailDBWriter::recordAtomicSourceRange(const SourceRange& sourceRange)
{
if (!m_storage)
{
m_lastError = "Unable to record comment location, because no database is currently open.";
m_lastError = "Unable to record atomic source range, because no database is currently open.";
return false;
}
try
{
const int sourceLocationId = m_storage->addSourceLocation(StorageSourceLocationData(
location.fileId,
location.startLine,
location.startColumn,
location.endLine,
location.endColumn,
locationKindToInt(LocationKind::COMMENT)
sourceRange.fileId,
sourceRange.startLine,
sourceRange.startColumn,
sourceRange.endLine,
sourceRange.endColumn,
locationKindToInt(LocationKind::ATOMIC_RANGE)
));
return true;
@@ -765,4 +831,13 @@ namespace sourcetrail
sourceLocationId
));
}
void SourcetrailDBWriter::addElementComponent(int elementId, ElementComponentKind kind, const std::string& data)
{
const int sourceLocationId = m_storage->addElementComponent(StorageElementComponentData(
elementId,
elementComponentKindToInt(kind),
data
));
}
}
+55 -4
View File
@@ -276,6 +276,57 @@ namespace sourcetrail
REQUIRE(writer.getLastError() == "");
}
TEST_CASE("Testing SourcetrailDBWriter records qualifier locations")
{
const std::string databasePath = "testing.db";
std::shared_ptr<DatabaseStorage> storage = DatabaseStorage::openDatabase(databasePath);
SourcetrailDBWriter writer;
REQUIRE(writer.getLastError() == "");
writer.open(databasePath);
REQUIRE(writer.getLastError() == "");
writer.clear();
REQUIRE(writer.getLastError() == "");
const NameHierarchy nameSymbol1({ "." ,{ { "", "Foo", "" } } });
const int idSymbol1 = writer.recordSymbol(nameSymbol1);
REQUIRE(idSymbol1 != 0);
REQUIRE(writer.getLastError() == "");
const std::string filePath = "path/to/non_existing_file.cpp";
const int fileId = writer.recordFile(filePath);
const int startLine = 1;
const int startCol = 2;
const int endLine = 3;
const int endCol = 4;
const bool success = writer.recordQualifierLocation(idSymbol1, { fileId, startLine, startCol, endLine, endCol });
REQUIRE(success);
REQUIRE(writer.getLastError() == "");
SECTION("database contains qualifier location after recording qualifier location")
{
const std::vector<StorageSourceLocation> sourceLocations = storage->getAll<StorageSourceLocation>();
REQUIRE(sourceLocations.size() == 1);
REQUIRE(sourceLocations.front().locationKind == locationKindToInt(LocationKind::QUALIFIER));
REQUIRE(sourceLocations.front().startLineNumber == startLine);
REQUIRE(sourceLocations.front().startColumnNumber == startCol);
REQUIRE(sourceLocations.front().endLineNumber == endLine);
REQUIRE(sourceLocations.front().endColumnNumber == endCol);
const std::vector<StorageFile> files = storage->getAll<StorageFile>();
REQUIRE(files.size() == 1);
REQUIRE(files.front().filePath == filePath);
REQUIRE(sourceLocations.front().fileNodeId == files.front().id);
}
writer.close();
REQUIRE(writer.getLastError() == "");
}
TEST_CASE("Testing SourcetrailDBWriter records file")
{
const std::string databasePath = "testing.db";
@@ -435,7 +486,7 @@ namespace sourcetrail
const int endLine = 3;
const int endCol = 4;
const bool success1 = writer.recordCommentLocation(
const bool success1 = writer.recordAtomicSourceRange(
{ fileId, startLine, startCol, endLine, endCol }
);
REQUIRE(success1);
@@ -445,7 +496,7 @@ namespace sourcetrail
{
const std::vector<StorageSourceLocation> sourceLocations = storage->getAll<StorageSourceLocation>();
REQUIRE(sourceLocations.size() == 1);
REQUIRE(sourceLocations.front().locationKind == locationKindToInt(LocationKind::COMMENT));
REQUIRE(sourceLocations.front().locationKind == locationKindToInt(LocationKind::ATOMIC_RANGE));
REQUIRE(sourceLocations.front().startLineNumber == startLine);
REQUIRE(sourceLocations.front().startColumnNumber == startCol);
REQUIRE(sourceLocations.front().endLineNumber == endLine);
@@ -457,9 +508,9 @@ namespace sourcetrail
REQUIRE(sourceLocations.front().fileNodeId == files.front().id);
}
SECTION("writer does not record comment location twice")
SECTION("writer does not record atomic source range twice")
{
const bool success2 = writer.recordCommentLocation(
const bool success2 = writer.recordAtomicSourceRange(
{ fileId, startLine, startCol, endLine, endCol }
);
REQUIRE(success2);
+29 -5
View File
@@ -4,6 +4,17 @@
#include "SourcetrailDBWriter.h"
void findAndReplaceAll(std::string &data, const std::string &toSearch, const std::string &replaceStr)
{
size_t pos = data.find(toSearch);
while (pos != std::string::npos)
{
data.replace(pos, toSearch.size(), replaceStr);
pos = data.find(toSearch, pos + replaceStr.size());
}
}
int main(int argc, const char *argv[])
{
sourcetrail::SourcetrailDBWriter dbWriter;
@@ -21,6 +32,7 @@ int main(int argc, const char *argv[])
std::string dbPath = argv[1];
std::string sourcePath = argv[2];
findAndReplaceAll(sourcePath, "\\", "/");
int dbVersion = 0;
if (argc == 4)
@@ -44,6 +56,13 @@ int main(int argc, const char *argv[])
return 1;
}
std::cout << "Clearing Database... " << std::endl;
if (!dbWriter.clear())
{
std::cerr << "error: " << dbWriter.getLastError() << std::endl;
return 1;
}
std::cout << "Starting Indexing..." << std::endl;
// start recording with faster speed
@@ -58,8 +77,8 @@ int main(int argc, const char *argv[])
dbWriter.recordFileLanguage(fileId, "cpp"); // record file language for syntax highlighting
// record comment
dbWriter.recordCommentLocation({ fileId, 2, 1, 6, 3 });
// record atomic source range for multi line comment
dbWriter.recordAtomicSourceRange({ fileId, 2, 1, 6, 3 });
// record namespace "api"
@@ -83,7 +102,7 @@ int main(int argc, const char *argv[])
// record inheritance reference to "BaseType"
int baseId = dbWriter.recordSymbol( { "::", { { "", "BaseType", "" } } } );
int inheritanceId = dbWriter.recordReference(baseId, classId, sourcetrail::ReferenceKind::INHERITANCE);
int inheritanceId = dbWriter.recordReference(classId, baseId, sourcetrail::ReferenceKind::INHERITANCE);
dbWriter.recordReferenceLocation(inheritanceId, { fileId, 12, 14, 12, 21 });
@@ -98,7 +117,7 @@ int main(int argc, const char *argv[])
dbWriter.recordSymbolSignatureLocation(methodId, { fileId, 15, 5, 15, 45 }); // used in tooltip
// record parameter type "bool"
// record usage of parameter type "bool"
int typeId = dbWriter.recordSymbol({ "::", { { "", "bool", "" } } });
int typeuseId = dbWriter.recordReference(methodId, typeId, sourcetrail::ReferenceKind::TYPE_USAGE);
dbWriter.recordReferenceLocation(typeuseId, { fileId, 15, 20, 15, 23 });
@@ -110,11 +129,16 @@ int main(int argc, const char *argv[])
dbWriter.recordLocalSymbolLocation(localId, { fileId, 17, 13, 17, 26 });
// record source range of "Client" as qualifier location
int qualifierId = dbWriter.recordSymbol({ "::",{ { "", "Client", "" } } });
dbWriter.recordQualifierLocation(qualifierId, { fileId, 19, 13, 19, 18 });
// record function call reference to "send_signal()"
int funcId = dbWriter.recordSymbol({ "::", { { "", "Client", "" }, { "", "send_signal", "()" } } });
dbWriter.recordSymbolKind(funcId, sourcetrail::SymbolKind::FUNCTION);
int callId = dbWriter.recordReference(methodId, funcId, sourcetrail::ReferenceKind::CALL);
dbWriter.recordReferenceLocation(callId, { fileId, 19, 13, 19, 33 });
dbWriter.recordReferenceLocation(callId, { fileId, 19, 21, 19, 31 });
// record error
+3 -5
View File
@@ -13,7 +13,7 @@ def main():
args = parser.parse_args()
databaseFilePath = args.database_file_path
sourceFilePath = args.source_file_path
sourceFilePath = args.source_file_path.replace("\\", "/")
dbVersion = args.database_version
print("SourcetrailDB Python API Example")
@@ -28,10 +28,8 @@ def main():
print("ERROR: " + srctrl.getLastError())
return 1
if srctrl.isEmpty():
print("Loaded database is empty.")
else:
print("Loaded database contains data.")
print("Clearing loaded database now...")
srctrl.clear()
print("start indexing")
srctrl.beginTransaction()
Binary file not shown.

After

Width:  |  Height:  |  Size: 669 KiB

+9 -1
View File
@@ -51,6 +51,8 @@ enum ReferenceKind
REFERENCE_ANNOTATION_USAGE
};
std::string getVersionString();
int getSupportedDatabaseVersion();
std::string getLastError();
@@ -93,6 +95,12 @@ int recordReference(int contextSymbolId, int referencedSymbolId, ReferenceKind r
bool recordReferenceLocation(int referenceId, int fileId, int startLine, int startColumn, int endLine, int endColumn);
bool recordReferenceIsAmbiuous(int referenceId);
int recordReferenceToUnsolvedSymhol(int contextSymbolId, ReferenceKind referenceKind, int fileId, int startLine, int startColumn, int endLine, int endColumn);
bool recordQualifierLocation(int referencedSymbolId, int fileId, int startLine, int startColumn, int endLine, int endColumn);
int recordFile(std::string filePath);
bool recordFileLanguage(int fileId, std::string languageIdentifier);
@@ -101,7 +109,7 @@ int recordLocalSymbol(std::string name);
bool recordLocalSymbolLocation(int localSymbolId, int fileId, int startLine, int startColumn, int endLine, int endColumn);
bool recordCommentLocation(int fileId, int startLine, int startColumn, int endLine, int endColumn);
bool recordAtomicSourceRange(int fileId, int startLine, int startColumn, int endLine, int endColumn);
bool recordError(std::string message, bool fatal, int fileId, int startLine, int startColumn, int endLine, int endColumn);
+22 -2
View File
@@ -108,6 +108,11 @@ namespace
sourcetrail::SourcetrailDBWriter dbWriter;
std::string getVersionString()
{
return dbWriter.getVersionString();
}
int getSupportedDatabaseVersion()
{
return dbWriter.getSupportedDatabaseVersion();
@@ -220,6 +225,21 @@ bool recordReferenceLocation(int referenceId, int fileId, int startLine, int sta
return dbWriter.recordReferenceLocation(referenceId, { fileId, startLine, startColumn, endLine, endColumn });
}
bool recordReferenceIsAmbiuous(int referenceId)
{
return dbWriter.recordReferenceIsAmbiuous(referenceId);
}
int recordReferenceToUnsolvedSymhol(int contextSymbolId, ReferenceKind referenceKind, int fileId, int startLine, int startColumn, int endLine, int endColumn)
{
return dbWriter.recordReferenceToUnsolvedSymhol(contextSymbolId, convertReferenceKind(referenceKind), { fileId, startLine, startColumn, endLine, endColumn });
}
bool recordQualifierLocation(int referencedSymbolId, int fileId, int startLine, int startColumn, int endLine, int endColumn)
{
return dbWriter.recordQualifierLocation(referencedSymbolId, { fileId, startLine, startColumn, endLine, endColumn });
}
int recordFile(std::string filePath)
{
return dbWriter.recordFile(filePath);
@@ -240,9 +260,9 @@ bool recordLocalSymbolLocation(int localSymbolId, int fileId, int startLine, int
return dbWriter.recordLocalSymbolLocation(localSymbolId, { fileId, startLine, startColumn, endLine, endColumn });
}
bool recordCommentLocation(int fileId, int startLine, int startColumn, int endLine, int endColumn)
bool recordAtomicSourceRange(int fileId, int startLine, int startColumn, int endLine, int endColumn)
{
return dbWriter.recordCommentLocation({ fileId, startLine, startColumn, endLine, endColumn });
return dbWriter.recordAtomicSourceRange({ fileId, startLine, startColumn, endLine, endColumn });
}
bool recordError(std::string message, bool fatal, int fileId, int startLine, int startColumn, int endLine, int endColumn)
+1
View File
@@ -0,0 +1 @@
v2.db24.p0
-1
View File
@@ -1 +0,0 @@
@VERSION_STRING_UNDERSCORE@