Update Index.

This commit is contained in:
ykiko
2024-10-17 21:51:20 +08:00
parent 035de84264
commit 14c9f9466d
10 changed files with 132 additions and 105 deletions

11
.vscode/launch.json vendored
View File

@@ -37,6 +37,17 @@
"--gtest_filter=clice.TemplateResolver"
],
"cwd": "${workspaceFolder}"
},
{
"type": "lldb",
"request": "launch",
"name": "Index",
"program": "${workspaceFolder}/build/bin/clice_test",
"args": [
"--test-dir=/home/ykiko/C++/clice2/tests/Source",
"--gtest_filter=clice.Index"
],
"cwd": "${workspaceFolder}"
}
]
}

View File

@@ -3,7 +3,7 @@
#include <Support/ADT.h>
#include <Protocol/Basic.h>
#include "SymbolID.h"
#include <Index/Symbol.h>
namespace clice {
@@ -33,8 +33,9 @@ struct CSIF {
llvm::ArrayRef<Symbol> symbols;
/// The occurrences in the source file.
llvm::ArrayRef<Occurrence> occurrences;
/// The semantic tokens in the source file.
llvm::ArrayRef<std::uint32_t> semanticTokens;
///// The semantic tokens in the source file.
// llvm::ArrayRef<std::uint32_t> semanticTokens;
// FIXME:
/// The diagnostics in the source file.
@@ -53,7 +54,7 @@ enum Role {
Override,
Write,
Read,
ExplicitInstantiation,
ImplicitInstantiation,
// TODO:
@@ -83,7 +84,7 @@ enum class SymbolKind {
struct Symbol {
/// The ID of the symbol.
SymbolID id;
SymbolID ID;
/// display when hover.
llvm::StringRef document;
@@ -97,7 +98,7 @@ struct Occurrence {
/// The ID of the symbol.
SymbolID symbol;
/// The range of the occurrence.
// Range range;
protocol::Range range;
/// The role of the occurrence.
Role role;
};

View File

@@ -1,10 +0,0 @@
#pragma once
#include <Index/CSIF.h>
#include <Compiler/Compiler.h>
namespace clice {
CSIF index(clang::ASTContext& context);
}

View File

@@ -0,0 +1,38 @@
#pragma once
#include <Index/CSIF.h>
namespace clice {
class SymbolSlab {
public:
SymbolSlab& addSymbol(const clang::Decl* decl);
SymbolSlab& addOccurrence(const clang::Decl* decl, protocol::Range range, Role role);
SymbolSlab& addRelation(const clang::Decl* from, const clang::Decl* to, Role role);
std::size_t lookup(const clang::Decl* decl) {
auto iter = cache.find(decl);
if(iter != cache.end()) {
return iter->second;
}
llvm::outs() << "SymbolSlab::lookup: decl not found\n";
std::terminate();
}
CSIF index(clang::ASTContext& context);
private:
llvm::BumpPtrAllocator allocator;
llvm::StringSaver saver{allocator};
std::vector<Symbol> symbols;
std::vector<Occurrence> occurrences;
std::vector<std::vector<Relation>> relations;
llvm::DenseMap<const clang::Decl*, std::size_t> cache;
};
} // namespace clice

View File

@@ -1,8 +1,8 @@
#pragma once
#include <array>
#include <llvm/Support/JSON.h>
#include <Support/Reflection.h>
#include <array>
namespace clice::json {
@@ -17,6 +17,9 @@ constexpr inline bool is_array_v<std::array<T, N>> = true;
template <typename T, typename A>
constexpr inline bool is_array_v<std::vector<T, A>> = true;
template <typename T>
constexpr inline bool is_array_v<llvm::ArrayRef<T>> = true;
template <typename T>
constexpr inline bool is_string_v = false;
@@ -31,7 +34,8 @@ constexpr inline bool is_string_v<llvm::StringRef> = true;
template <typename T>
constexpr inline bool is_integral_v =
std::is_same_v<T, int> || std::is_same_v<T, unsigned> || std::is_same_v<T, long> || std::is_same_v<T, long long>;
std::is_same_v<T, int> || std::is_same_v<T, unsigned> || std::is_same_v<T, long> ||
std::is_same_v<T, unsigned long> || std::is_same_v<T, long long> || std::is_same_v<T, unsigned long long>;
template <typename Value>
json::Value serialize(const Value& value) {

View File

@@ -1 +1 @@
cmake -B build -G Ninja -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug -DCLICE_ENABLE_TEST=ON -DCMAKE_CXX_FLAGS="-fno-rtti -g -O0"
cmake -B build -G Ninja -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug -DCLICE_ENABLE_TEST=ON -DCMAKE_CXX_FLAGS="-fno-rtti -g -O0 -fsanitize=address"

View File

@@ -1,71 +1,15 @@
#include <Index/Index.h>
#include <Index/SymbolSlab.h>
#include <clang/Index/USRGeneration.h>
namespace clice {
namespace {
class SymbolBuilder {
public:
CSIF dump() {
CSIF csif;
csif.version = "0.0.1";
csif.language = "C++";
csif.symbols = symbols;
csif.occurrences = occurrences;
return csif;
}
std::size_t addSymbolID(const clang::Decl* decl) {
auto iter = cache.find(decl);
if(iter != cache.end()) {
return iter->second;
}
// Generate and save USR.
llvm::SmallString<128> USR;
clang::index::generateUSRForDecl(decl, USR);
saver.save(USR.str());
auto index = symbols.size();
cache[decl] = index;
return index;
}
SymbolBuilder& addSymbol(const clang::Decl* decl) {
return *this;
}
SymbolBuilder& addRelation(const clang::Decl* from, const clang::Decl* to, Role role) {
// FIXME:
return *this;
}
// TODO:
SymbolBuilder& addOccurrence() {
return *this;
}
template <typename Node, typename Callback>
bool hook(Node* node, const Callback& callback) {
return true;
}
private:
std::vector<Symbol> symbols;
std::vector<Occurrence> occurrences;
std::vector<std::vector<Relation>> relations;
llvm::DenseMap<const clang::Decl*, std::size_t> cache;
llvm::BumpPtrAllocator allocator;
llvm::StringSaver saver{allocator};
};
class SymbolCollector : public clang::RecursiveASTVisitor<SymbolCollector> {
using Base = clang::RecursiveASTVisitor<SymbolCollector>;
public:
SymbolCollector(SymbolBuilder& builder) : builder(builder) {}
SymbolCollector(SymbolSlab& builder) : builder(builder) {}
bool TraverseDecl(clang::Decl* decl) {
/// `TranslationUnitDecl` has invalid location information.
@@ -74,27 +18,22 @@ public:
return Base::TraverseDecl(decl);
}
builder.addSymbol(decl);
// TODO: generate SymbolID for every decl.
// Distinguish linkage, for no or internal linkage.
// For them, relation lookup is only occurred in current TU.
return builder.hook(decl, [&] {
return Base::TraverseDecl(decl);
});
return Base::TraverseDecl(decl);
}
// FIXME: check DeclRefExpr, MemberExpr, etc.
bool TraverseStmt(clang::Stmt* stmt) {
return builder.hook(stmt, [&] {
return Base::TraverseStmt(stmt);
});
return Base::TraverseStmt(stmt);
}
bool TraverseAttr(clang::Attr* attr) {
return builder.hook(attr, [&] {
return Base::TraverseAttr(attr);
});
return Base::TraverseAttr(attr);
}
/// we don't care about the node without location information, so skip them.
@@ -117,27 +56,19 @@ public:
return TraverseTypeLoc(QTL.getUnqualifiedLoc());
}
return builder.hook(&loc, [&] {
return Base::TraverseTypeLoc(loc);
});
return Base::TraverseTypeLoc(loc);
}
bool TraverseTemplateArgumentLoc(const clang::TemplateArgumentLoc& argument) {
return builder.hook(&argument, [&] {
return Base::TraverseTemplateArgumentLoc(argument);
});
return Base::TraverseTemplateArgumentLoc(argument);
}
bool TraverseCXXBaseSpecifier(const clang::CXXBaseSpecifier& base) {
return builder.hook(&base, [&] {
return Base::TraverseCXXBaseSpecifier(base);
});
return Base::TraverseCXXBaseSpecifier(base);
}
bool TraverseConstructorInitializer(clang::CXXCtorInitializer* init) {
return builder.hook(init, [&] {
return Base::TraverseConstructorInitializer(init);
});
return Base::TraverseConstructorInitializer(init);
}
bool VisiDeclRefExpr(const clang::DeclRefExpr* expr) {
@@ -191,6 +122,7 @@ public:
VISIT_TYOELOC(ElaboratedTypeLoc) {
auto loc1 = loc.getElaboratedKeywordLoc();
return true;
// render keyword.
}
@@ -208,16 +140,21 @@ public:
// MemberPointerTypeLoc
private:
SymbolBuilder& builder;
SymbolSlab& builder;
};
} // namespace
CSIF index(clang::ASTContext& context) {
SymbolBuilder builder;
SymbolCollector collector(builder);
CSIF SymbolSlab::index(clang::ASTContext& context) {
CSIF csif;
SymbolCollector collector(*this);
collector.TraverseAST(context);
return builder.dump();
csif.version = "0.1";
csif.language = "C++";
csif.symbols = symbols;
csif.occurrences = occurrences;
return csif;
};
} // namespace clice

37
src/Index/SymbolSlab.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include <Index/SymbolSlab.h>
#include <clang/Index/USRGeneration.h>
namespace clice {
SymbolSlab& SymbolSlab::addSymbol(const clang::Decl* decl) {
// Generate and save USR.
llvm::SmallString<128> USR;
clang::index::generateUSRForDecl(decl, USR);
saver.save(USR.str());
if(cache.contains(decl)) {
llvm::outs() << "SymbolSlab::addSymbol: decl already exists\n";
std::terminate();
}
auto index = symbols.size();
symbols.emplace_back(SymbolID::fromUSR(USR.str()));
cache.try_emplace(decl, index);
return *this;
}
SymbolSlab& SymbolSlab::addOccurrence(const clang::Decl* decl, protocol::Range range, Role role) {
auto ID = symbols[lookup(decl)].ID;
occurrences.emplace_back(Occurrence{ID, range, role});
return *this;
}
SymbolSlab& SymbolSlab::addRelation(const clang::Decl* from, const clang::Decl* to, Role role) {
std::size_t index = lookup(from);
SymbolID fromID = symbols[index].ID;
SymbolID toID = symbols[lookup(to)].ID;
relations[index].emplace_back(Relation{toID, role});
return *this;
}
} // namespace clice

View File

@@ -1,9 +1,11 @@
#include <gtest/gtest.h>
#include <Index/Index.h>
#include <Index/SymbolSlab.h>
#include <Support/JSON.h>
#include <Compiler/Compiler.h>
using namespace clice;
TEST(clice_test, index) {
TEST(clice, Index) {
std::vector<const char*> compileArgs = {
"clang++",
"-std=c++20",
@@ -21,4 +23,11 @@ void f() {
X<int, int> x;
}
)";
Compiler compiler("main.cpp", code, compileArgs);
compiler.buildAST();
SymbolSlab slab;
auto csif = slab.index(compiler.context());
auto value = json::serialize(csif);
llvm::outs() << value << "\n";
}