some update.

This commit is contained in:
ykiko
2024-08-05 11:20:13 +08:00
parent c975cbf683
commit 0be4391cf5
14 changed files with 731 additions and 161 deletions

2
.vscode/launch.json vendored
View File

@@ -18,7 +18,7 @@
"name": "Launch",
"program": "${workspaceFolder}/build/ASTVisitor",
"args": [
"/home/ykiko/Project/C++/clice/main.cpp",
"/home/ykiko/C++/clice/main.cpp",
],
"cwd": "${workspaceFolder}"
},

View File

@@ -1,32 +1,32 @@
cmake_minimum_required(VERSION 3.22)
project(clice)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_CXX_FLAGS "-isystem/usr/include/c++/13 -isystem/usr/include/x86_64-linux-gnu/c++/13 ${CMAKE_CXX_FLAGS_RELEASE} -g -O0 -fno-rtti")
set(CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/external/llvm/lib/cmake")
find_package(LLVM REQUIRED CONFIG)
find_package(Clang REQUIRED CONFIG)
message(STATUS "LLVM_INCLUDE_DIRS: ${LLVM_INCLUDE_DIRS}")
set(PCH_HEADER "${CMAKE_SOURCE_DIR}/include/Clang/Clang.h")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_RELEASE} -w -g -O0 -fno-rtti")
set(JSON_BuildTests OFF CACHE INTERNAL "")
set(LLVM_ENABLE_PROJECTS "clang")
set(LLVM_TARGETS_TO_BUILD "X86")
set(LLVM_USE_LINKER "lld")
set(BUILD_SHARED_LIBS ON)
set(LLVM_ABI_BREAKING_CHECKS "FORCE_OFF")
add_subdirectory("${CMAKE_SOURCE_DIR}/external/llvm-project/llvm")
add_subdirectory("${CMAKE_SOURCE_DIR}/external/json")
add_subdirectory("${CMAKE_SOURCE_DIR}/external/libuv")
add_subdirectory("${CMAKE_SOURCE_DIR}/external/spdlog")
set(INCLUDE_DIRS
"${CMAKE_SOURCE_DIR}/include"
"${CMAKE_SOURCE_DIR}/external/llvm-project/clang/lib/Sema"
"${CMAKE_SOURCE_DIR}/external/json/include"
"${CMAKE_SOURCE_DIR}/external/libuv/include"
"${CMAKE_SOURCE_DIR}/external/spdlog/include"
"${CMAKE_SOURCE_DIR}/external/llvm/include"
"${CMAKE_SOURCE_DIR}/external/llvm/tools/clang/include"
)
set(PCH_HEADER "${CMAKE_SOURCE_DIR}/include/Clang/Clang.h")
set(LLVM_LIBS
LLVMCore
LLVMSupport
@@ -46,6 +46,7 @@ set(LLVM_LIBS
clangToolingInclusions
clangToolingInclusionsStdlib
clangToolingSyntax
LLVMFrontendOpenMP
)
set(LINK_LIBS
@@ -90,4 +91,5 @@ if(CLICE_EXAMPLES)
add_example(CodeCompletion docs/examples/CodeCompletion.cpp)
add_example(Preamble docs/examples/Preamble.cpp)
add_example(Preprocessor docs/examples/Preprocessor.cpp)
add_example(TreeTransform docs/examples/TreeTransform.cpp)
endif()

View File

@@ -24,6 +24,7 @@ FIXME:
- no-self-contained: https://github.com/clangd/clangd/issues/45
- 提供更好的模板代码补全需要在索引文件里面记录模板实例化https://github.com/clangd/clangd/issues/443然后补全的时候获取`.`号前面的表达式类型,之后再这里查找
- 支持模块https://github.com/clangd/clangd/issues/1293
- https://github.com/clangd/clangd/issues/123 优化头文查找
## 性能优化
TODO: 寻找核心优化点

View File

@@ -77,4 +77,35 @@
2. Semantic Tokens 等基于当前 AST 的操作,则是遍历 AST 渲染 Token 即可。
3. 剩下很多的,例如 Find References 等等等查询功能,都是在已经索引好的文件中进行查询,不需要对语法树进行什么改动。
###
### DependentNameResolver
对于一个`DependentNameType`我们要分情况处理
最一般的`DependentNameType`可以用如下形式的正则表达式处理 `typename T<...>[::T2|::template T2<...>]*`
首先我们要讨论希望化简到什么结果,例如对于
```cpp
typename std::vector<std::vector<T>>::reference
```
我们希望得到
```cpp
std::vector<T>&
```
对于
```cpp
typename std::vector<std::vector<T>>::value_type::reference
```
我们希望得到
```cpp
T&
```
无论如何我们需要递归进行处理

View File

@@ -1,5 +1,6 @@
#include <Clang/Clang.h>
#include <clang/Sema/Lookup.h>
#include <clang/Sema/Template.h>
class DependentShaper {
clang::ASTContext& context;
@@ -33,6 +34,15 @@ public:
}
clang::ElaboratedType* elaboratedType = nullptr;
clang::MultiLevelTemplateArgumentList list;
list.addOuterTemplateArguments(originalArguments);
llvm::outs() << "-------------------------------------------------\n";
clang::Sema::CodeSynthesisContext InstContext;
// InstContext.Kind = clang::Sema::CodeSynthesisContext::TemplateInstantiation;
// InstContext.Entity = nullptr;
// InstContext.TemplateArgs = TemplateArgs;
// sema.CodeSynthesisContexts.back().dump();
auto result = sema.SubstType(input, list, {}, {});
if(auto type = llvm::dyn_cast<clang::LValueReferenceType>(input)) {
auto pointee = type->getPointeeType();
@@ -147,6 +157,455 @@ public:
}
};
namespace clang {
class DependentNameResolver {
public:
Sema& S;
ASTContext& Ctx;
clang::NamedDecl* CurrentDecl;
public:
DependentNameResolver(ASTContext& Ctx, Sema& S) : Ctx(Ctx), S(S) {}
std::vector<TemplateArgument> resolve(llvm::ArrayRef<TemplateArgument> arguments) {
std::vector<TemplateArgument> result;
for(auto arg: arguments) {
if(arg.getKind() == TemplateArgument::ArgKind::Type) {
if(auto type = llvm::dyn_cast<TemplateTypeParmType>(arg.getAsType())) {
const TemplateTypeParmDecl* param = type->getDecl();
if(param->hasDefaultArgument()) {
result.push_back(param->getDefaultArgument().getArgument());
continue;
}
}
}
result.push_back(arg);
}
return result;
}
QualType resolve(QualType T) {
if(!T->isDependentType()) {
return T;
}
while(true) {
if(auto DNT = T->getAs<DependentNameType>()) {
T = resolve(DNT);
} else if(auto DTST = T->getAs<DependentTemplateSpecializationType>()) {
T = resolve(DTST);
} else if(auto LRT = T->getAs<LValueReferenceType>()) {
return Ctx.getLValueReferenceType(resolve(LRT->getPointeeType()));
} else {
return T;
}
}
}
/// resolve a dependent name type, e.g. `typename std::vector<T>::reference`
QualType resolve(const DependentNameType* DNT) {
// e.g. when DNT is `typename std::vector<T>::reference`
// - qualifier: std::vector<T>
// - identifier: reference
return resolve(DNT->getQualifier(), DNT->getIdentifier());
}
/// resolve a dependent template specialization type.
QualType resolve(const DependentTemplateSpecializationType* DTST) {
// e.g. when DTST is `typename std::allocator_traits<Alloc>::template rebind_alloc<T>`.
// - qualifier: std::allocator_traits<Alloc>
// - identifier: rebind_alloc
// - template_arguments: <T>
return resolve(DTST->getQualifier(), DTST->getIdentifier(), DTST->template_arguments());
}
QualType resolve(const NestedNameSpecifier* TST,
const IdentifierInfo* II,
ArrayRef<TemplateArgument> arguments = {}) {
switch(TST->getKind()) {
case NestedNameSpecifier::SpecifierKind::Identifier: {
llvm::outs() << "\n------------------ Identifier -----------------------\n";
// when the kind of TST is Identifier
// e.g. std::vector<std::vector<T>>::value_type::
// resolve it recursively
return resolve(resolve(TST->getPrefix(), TST->getAsIdentifier()), II, arguments);
}
case NestedNameSpecifier::SpecifierKind::TypeSpec: {
llvm::outs() << "\n------------------ TypeSpec -----------------------\n";
TST->dump();
llvm::outs() << " " << II->getName() << "\n";
// when the kind of TST is TypeSpec, e.g. std::vector<T>::
return resolve(QualType(TST->getAsType(), 0), II, arguments);
}
case NestedNameSpecifier::SpecifierKind::TypeSpecWithTemplate: {
llvm::outs() << "------------------ TypeSpecWithTemplate -----------------------\n";
// when the kind of TST is TypeSpecWithTemplate, e.g. std::vector<T>::template name<U>::
TST->dump();
return resolve(QualType(TST->getAsType(), 0), II, arguments);
}
default: {
llvm::outs() << "\n------------------ Unknown -----------------------\n";
TST->dump();
std::terminate();
}
}
}
QualType substitute(ClassTemplateDecl* CTD,
const IdentifierInfo* II,
ArrayRef<TemplateArgument> arguments = {}) {
Sema::CodeSynthesisContext context;
auto args = resolve(arguments);
context.Entity = CTD;
context.TemplateArgs = args.data();
context.Kind = Sema::CodeSynthesisContext::TemplateInstantiation;
S.pushCodeSynthesisContext(context);
MultiLevelTemplateArgumentList list;
auto recordDecl = CTD->getTemplatedDecl();
auto member = recordDecl->lookup(II).front();
QualType type;
if(auto TAD = llvm::dyn_cast<TypeAliasDecl>(member)) {
type = TAD->getUnderlyingType();
} else if(auto TD = llvm::dyn_cast<TypedefDecl>(member)) {
type = TD->getUnderlyingType();
} else if(auto TATD = llvm::dyn_cast<TypeAliasTemplateDecl>(member)) {
auto args2 = resolve(arguments);
context.Entity = TATD;
context.TemplateArgs = args2.data();
context.Kind = Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation;
S.pushCodeSynthesisContext(context);
MultiLevelTemplateArgumentList list;
list.addOuterTemplateArguments(TATD, args2, false);
auto TAD = TATD->getTemplatedDecl();
type = TAD->getUnderlyingType();
} else if(auto CTD = llvm::dyn_cast<ClassTemplateDecl>(member)) {
return substitute(CTD, II, arguments);
} else {
member->dump();
std::terminate();
}
list.addOuterTemplateArguments(CTD, args, true);
return S.SubstType(type, list, {}, {});
}
/// typename A<U1>::template B<U2>::template C<U3>::type::
QualType resolve(const DependentTemplateSpecializationType* DTST, const IdentifierInfo* II) {
// auto prefix;
MultiLevelTemplateArgumentList list;
while(true) {
// list.addOuterTemplateArguments()
}
}
QualType resolve(QualType T, const IdentifierInfo* II, ArrayRef<TemplateArgument> arguments = {}) {
if(!T->isDependentType() && arguments.size() == 0) {
// TODO:
}
llvm::outs() << "\n";
T.dump();
Sema::CodeSynthesisContext context;
if(auto TTPT = T->getAs<TemplateTypeParmType>()) {
llvm::outs() << "\n-------------------------------------------------\n";
T->dump();
llvm::outs() << " \n" << II->getName();
// e.g. when T is `T`
// - index: 0
} else if(auto TST = T->getAs<TemplateSpecializationType>()) {
auto TemplateName = TST->getTemplateName();
auto TemplateDecl = TemplateName.getAsTemplateDecl();
auto TemplatedDecl = TemplateDecl->getTemplatedDecl();
if(auto CTD = llvm::dyn_cast<ClassTemplateDecl>(TemplateDecl)) {
return substitute(CTD, II, TST->template_arguments());
} else {
TemplateDecl->dump();
std::terminate();
}
auto TemplateArgs = TST->template_arguments();
} else if(auto DTST = T->getAs<DependentTemplateSpecializationType>()) {
auto TST = DTST->getQualifier()->getAsType()->getAs<TemplateSpecializationType>();
auto TemplateName = TST->getTemplateName();
auto TemplateDecl = TemplateName.getAsTemplateDecl();
auto TemplatedDecl = TemplateDecl->getTemplatedDecl();
if(auto CTD = llvm::dyn_cast<ClassTemplateDecl>(TemplateDecl)) {
auto args = resolve(TST->template_arguments());
context.Entity = CTD;
context.TemplateArgs = args.data();
context.Kind = Sema::CodeSynthesisContext::TemplateInstantiation;
S.pushCodeSynthesisContext(context);
MultiLevelTemplateArgumentList list;
list.addOuterTemplateArguments(CTD, args, true);
auto recordDecl = CTD->getTemplatedDecl();
auto member = recordDecl->lookup(DTST->getIdentifier()).front();
if(auto CTD2 = llvm::dyn_cast<ClassTemplateDecl>(member)) {
auto args2 = resolve(DTST->template_arguments());
context.Entity = CTD2;
context.TemplateArgs = args2.data();
context.Kind = Sema::CodeSynthesisContext::TemplateInstantiation;
S.pushCodeSynthesisContext(context);
MultiLevelTemplateArgumentList list;
list.addOuterTemplateArguments(CTD2, args2, true);
list.addOuterTemplateArguments(CTD, args, true);
auto CRD = CTD2->getTemplatedDecl();
return S.SubstType(
llvm::dyn_cast<TypeAliasDecl>(CRD->lookup(II).front())->getUnderlyingType(),
list,
{},
{});
} else if(auto TATD = llvm::dyn_cast<TypeAliasTemplateDecl>(member)) {
auto args2 = resolve(arguments);
context.Entity = TATD;
context.TemplateArgs = args2.data();
context.Kind = Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation;
S.pushCodeSynthesisContext(context);
MultiLevelTemplateArgumentList list;
list.addOuterTemplateArguments(TATD, args2, false);
list.addOuterTemplateArguments(CTD, args, true);
auto TAD = TATD->getTemplatedDecl();
return S.SubstType(TAD->getUnderlyingType(), list, {}, {});
} else {
member->dump();
std::terminate();
}
} else {
T->dump();
std::terminate();
}
// S.SubstType()
}
}
};
class DependentNameResolverV2 {
public:
Sema& S;
ASTContext& Ctx;
std::vector<std::pair<Decl*, std::vector<TemplateArgument>>*> arguments;
public:
DependentNameResolverV2(ASTContext& Ctx, Sema& S) : Ctx(Ctx), S(S) {}
std::vector<TemplateArgument> resolve(llvm::ArrayRef<TemplateArgument> arguments) {
std::vector<TemplateArgument> result;
for(auto arg: arguments) {
if(arg.getKind() == TemplateArgument::ArgKind::Type) {
if(auto type = llvm::dyn_cast<TemplateTypeParmType>(arg.getAsType())) {
const TemplateTypeParmDecl* param = type->getDecl();
if(param && param->hasDefaultArgument()) {
result.push_back(param->getDefaultArgument().getArgument());
continue;
}
}
}
result.push_back(arg);
}
return result;
}
QualType dealias(QualType type) {
if(auto DNT = type->getAs<TemplateSpecializationType>()) {
return QualType(DNT, 0);
} else if(auto DTST = type->getAs<DependentTemplateSpecializationType>()) {
auto NNS = NestedNameSpecifier::Create(
Ctx,
nullptr,
false,
dealias(QualType(DTST->getQualifier()->getAsType(), 0)).getTypePtr());
return Ctx.getDependentTemplateSpecializationType(DTST->getKeyword(),
NNS,
DTST->getIdentifier(),
resolve(DTST->template_arguments()));
} else {
return type;
}
}
QualType resolve(QualType type) {
while(true) {
// llvm::outs() << "--------------------------------------------------------------------\n";
// type.dump();
MultiLevelTemplateArgumentList list;
if(auto DNT = type->getAs<DependentNameType>()) {
type = resolve(resolve(DNT->getQualifier(), DNT->getIdentifier()));
for(auto begin = arguments.rbegin(), end = arguments.rend(); begin != end; ++begin) {
list.addOuterTemplateArguments((*begin)->first, (*begin)->second, true);
}
type = S.SubstType(dealias(type), list, {}, {});
arguments.clear();
} else if(auto DTST = type->getAs<DependentTemplateSpecializationType>()) {
auto ND = resolve(DTST->getQualifier(), DTST->getIdentifier());
if(auto TATD = llvm::dyn_cast<TypeAliasTemplateDecl>(ND)) {
auto args = resolve(DTST->template_arguments());
Sema::CodeSynthesisContext context;
context.Entity = TATD;
context.Kind = Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation;
context.TemplateArgs = args.data();
S.pushCodeSynthesisContext(context);
list.addOuterTemplateArguments(TATD, args, true);
for(auto begin = arguments.rbegin(), end = arguments.rend(); begin != end; ++begin) {
list.addOuterTemplateArguments((*begin)->first, (*begin)->second, true);
}
// llvm::outs() << "before:
// ----------------------------------------------------------------\n";
// TATD->getTemplatedDecl()->getUnderlyingType().dump();
type = dealias(TATD->getTemplatedDecl()->getUnderlyingType());
// llvm::outs() << "arguments:
// -------------------------------------------------------------\n"; list.dump();
type = S.SubstType(type, list, {}, {});
// type.dump();
arguments.clear();
} else {
ND->dump();
std::terminate();
}
// return resolve(DTST);
} else if(auto LRT = type->getAs<LValueReferenceType>()) {
type = Ctx.getLValueReferenceType(resolve(LRT->getPointeeType()));
} else {
return type;
}
}
}
QualType resolve(NamedDecl* ND) {
if(auto TD = llvm::dyn_cast<TypedefDecl>(ND)) {
return TD->getUnderlyingType();
} else if(auto TAD = llvm::dyn_cast<TypeAliasDecl>(ND)) {
return TAD->getUnderlyingType();
} else {
ND->dump();
std::terminate();
}
}
NamedDecl* resolve(const NestedNameSpecifier* NNS, const IdentifierInfo* II) {
switch(NNS->getKind()) {
// prefix is an identifier, e.g. <...>::name::
case NestedNameSpecifier::SpecifierKind::Identifier: {
return lookup(resolve(resolve(NNS->getPrefix(), NNS->getAsIdentifier())), II);
}
// prefix is a type, e.g. <...>::typename name::
case NestedNameSpecifier::SpecifierKind::TypeSpec:
case NestedNameSpecifier::SpecifierKind::TypeSpecWithTemplate: {
return lookup(QualType(NNS->getAsType(), 0), II);
}
default: {
NNS->dump();
std::terminate();
}
}
}
NamedDecl* lookup(QualType Type, const IdentifierInfo* Name) {
NamedDecl* TemplateDecl;
ArrayRef<TemplateArgument> arguments;
llvm::outs() << "--------------------------------------------------------------------\n";
Type.dump();
if(auto TTPT = Type->getAs<TemplateTypeParmType>()) {
Type->dump();
std::terminate();
} else if(auto TST = Type->getAs<TemplateSpecializationType>()) {
auto TemplateName = TST->getTemplateName();
TemplateDecl = TemplateName.getAsTemplateDecl();
arguments = TST->template_arguments();
} else if(auto DTST = Type->getAs<DependentTemplateSpecializationType>()) {
TemplateDecl = resolve(DTST->getQualifier(), DTST->getIdentifier());
arguments = DTST->template_arguments();
} else if(auto RT = Type->getAs<RecordType>()) {
return RT->getDecl()->lookup(Name).front();
} else {
Type->dump();
std::terminate();
}
this->arguments.push_back(
new std::pair<Decl*, std::vector<TemplateArgument>>{TemplateDecl, resolve(arguments)});
NamedDecl* result;
Sema::CodeSynthesisContext context;
context.Entity = TemplateDecl;
context.Kind = Sema::CodeSynthesisContext::TemplateInstantiation;
context.TemplateArgs = this->arguments.back()->second.data();
S.pushCodeSynthesisContext(context);
if(auto CTD = llvm::dyn_cast<ClassTemplateDecl>(TemplateDecl)) {
llvm::outs() << "--------------------------------------------------------------------\n";
llvm::SmallVector<ClassTemplatePartialSpecializationDecl*> paritals;
CTD->getPartialSpecializations(paritals);
for(auto partial: paritals) {
partial->getInjectedSpecializationType().dump();
}
llvm::outs() << "--------------------------------------------------------------------\n";
// CTD->findPartialSpecialization()
auto partial = CTD->findPartialSpecialization(Type);
if(partial) {
result = partial->lookup(Name).front();
}
if(!result) {
result = CTD->getTemplatedDecl()->lookup(Name).front();
}
} else if(auto TATD = llvm::dyn_cast<TypeAliasTemplateDecl>(TemplateDecl)) {
result = lookup(TATD->getTemplatedDecl()->getUnderlyingType(), Name);
}
if(result == nullptr) {
Type.dump();
std::terminate();
}
return result;
}
};
} // namespace clang
class ASTVistor : public clang::RecursiveASTVisitor<ASTVistor> {
private:
clang::Preprocessor& preprocessor;
@@ -165,15 +624,13 @@ public:
bool VisitTypeAliasDecl(clang::TypeAliasDecl* decl) {
auto& sm = context.getSourceManager();
if(sm.isInMainFile(decl->getLocation()) && decl->getName() == "type") {
if(sm.isInMainFile(decl->getLocation()) && decl->getName() == "result") {
auto type = decl->getUnderlyingType();
type.dump();
llvm::outs() << "----------------------------------------------------------------\n";
if(auto templateType = type->getAs<clang::DependentNameType>()) {
DependentShaper shaper{context};
auto result = shaper.simplify(templateType);
result->dump();
}
llvm::outs() << "--------------------------------- Result ------------------------------\n";
clang::DependentNameResolverV2 shaper{context, sema};
auto result = shaper.resolve(type);
result.dump();
}
return true;
@@ -194,7 +651,7 @@ int main(int argc, const char** argv) {
auto invocation = std::make_shared<clang::CompilerInvocation>();
std::vector<const char*> args = {
"/home/ykiko/Project/C++/clice/external/llvm/bin/clang++",
"/usr/local/bin/clang++",
"-Xclang",
"-no-round-trip-args",
"-std=c++20",

View File

@@ -29,67 +29,73 @@ public:
clang::CodeCompletionContext Context,
clang::CodeCompletionResult* Results,
unsigned NumResults) override {
auto contexts = Context.getVisitedContexts();
for(auto c: contexts) {
// llvm::outs() << " Kind: " << c->getDeclKindName() << "\n";
// for(auto d: c->decls()) {
// // d->dump();
// }
}
llvm::outs() << "code completion results:\n";
switch(Context.getKind()) {
case clang::CodeCompletionContext::CCC_Attribute: {
}
case clang::CodeCompletionContext::CCC_DotMemberAccess: {
const auto type = Context.getBaseType();
if(type->isDependentType()) {
if(const auto dependentType = type->getAs<clang::DependentNameType>()) {
auto qualifers = dependentType->getQualifier();
// qualifers->getKind() -> clang::NestedNameSpecifier::SpecifierKind;
// auto t = qualifers->getAsType();
// TODO: 看是否能根据主模板一路把依赖名替换下去,直到变成非依赖名
} else if(const auto dependentType = type->getAs<clang::TemplateSpecializationType>()) {
}
}
break;
}
/* ... */
default: {
llvm::outs() << " Kind: " << Context.getKind() << "\n";
}
}
for(unsigned i = 0; i < NumResults; ++i) {
clang::CodeCompletionResult& Result = Results[i];
switch(Result.Kind) {
case clang::CodeCompletionResult::RK_Declaration: {
llvm::outs() << " Declaration: ";
llvm::outs() << Result.Declaration->getNameAsString() << "\n";
break;
}
case clang::CodeCompletionResult::RK_Keyword: {
llvm::outs() << " Keyword: ";
llvm::outs() << Result.Keyword << "\n";
break;
}
case clang::CodeCompletionResult::RK_Macro: {
llvm::outs() << " Macro: ";
llvm::outs() << Result.Macro->getName() << "\n";
break;
}
case clang::CodeCompletionResult::RK_Pattern: {
llvm::outs() << " Pattern: ";
llvm::outs() << Result.Pattern->getAsString() << "\n";
break;
}
}
llvm::outs() << NumResults << " code completion results\n";
auto kind = Context.getKind();
if(kind == clang::CodeCompletionContext::CCC_DotMemberAccess) {
auto type = Context.getBaseType();
type->dump();
}
// auto contexts = Context.getVisitedContexts();
// for(auto c: contexts) {
// // llvm::outs() << " Kind: " << c->getDeclKindName() << "\n";
// // for(auto d: c->decls()) {
// // // d->dump();
// // }
// }
//
// llvm::outs() << "code completion results:\n";
// switch(Context.getKind()) {
// case clang::CodeCompletionContext::CCC_Attribute: {
// }
// case clang::CodeCompletionContext::CCC_DotMemberAccess: {
// const auto type = Context.getBaseType();
// if(type->isDependentType()) {
//
// if(const auto dependentType = type->getAs<clang::DependentNameType>()) {
// auto qualifers = dependentType->getQualifier();
// // qualifers->getKind() -> clang::NestedNameSpecifier::SpecifierKind;
// // auto t = qualifers->getAsType();
// // TODO: 看是否能根据主模板一路把依赖名替换下去,直到变成非依赖名
// } else if(const auto dependentType = type->getAs<clang::TemplateSpecializationType>()) {
// }
// }
// break;
// }
// /* ... */
// default: {
// llvm::outs() << " Kind: " << Context.getKind() << "\n";
// }
//}
//
// for(unsigned i = 0; i < NumResults; ++i) {
// clang::CodeCompletionResult& Result = Results[i];
//
// switch(Result.Kind) {
// case clang::CodeCompletionResult::RK_Declaration: {
// llvm::outs() << " Declaration: ";
// llvm::outs() << Result.Declaration->getNameAsString() << "\n";
// break;
// }
//
// case clang::CodeCompletionResult::RK_Keyword: {
// llvm::outs() << " Keyword: ";
// llvm::outs() << Result.Keyword << "\n";
// break;
// }
//
// case clang::CodeCompletionResult::RK_Macro: {
// llvm::outs() << " Macro: ";
// llvm::outs() << Result.Macro->getName() << "\n";
// break;
// }
//
// case clang::CodeCompletionResult::RK_Pattern: {
// llvm::outs() << " Pattern: ";
// llvm::outs() << Result.Pattern->getAsString() << "\n";
// break;
// }
// }
//}
}
void ProcessOverloadCandidates(clang::Sema& S,
@@ -109,13 +115,13 @@ int main(int argc, const char** argv) {
clang::DiagnosticIDs* ids = new clang::DiagnosticIDs();
clang::DiagnosticOptions* diag_opts = new clang::DiagnosticOptions();
diag_opts->IgnoreWarnings = true;
clang::DiagnosticConsumer* consumer = new clang::TextDiagnosticPrinter(llvm::errs(), diag_opts);
clang::DiagnosticConsumer* consumer = new clang::IgnoringDiagConsumer();
clang::DiagnosticsEngine* engine = new clang::DiagnosticsEngine(ids, diag_opts, consumer);
instance->setDiagnostics(engine);
auto invocation = std::make_shared<clang::CompilerInvocation>();
std::vector<const char*> args = {
"/home/ykiko/Project/C++/clice/external/llvm/bin/clang++",
"/usr/local/bin/clang++",
"-Xclang",
"-no-round-trip-args",
"-std=c++20",

View File

@@ -0,0 +1,130 @@
#include <Clang/Clang.h>
#include <clang/Sema/Lookup.h>
#include <clang/Sema/Template.h>
#include <TreeTransform.h>
#include <clang/Sema/SemaConsumer.h>
namespace clang {
class MyTreeTransform : public TreeTransform<MyTreeTransform> {
ASTContext& Context;
public:
MyTreeTransform(Sema& SemaRef, clang::ASTContext& Context) :
TreeTransform<MyTreeTransform>(SemaRef), Context(Context) {}
ExprResult TransformBinaryOperator(BinaryOperator* E) {
llvm::outs() << "Transforming BinaryOperator\n";
E->dump();
auto LHS = TransformExpr(E->getLHS());
auto RHS = TransformExpr(E->getRHS());
return SemaRef.BuildBinOp(SemaRef.getCurScope(),
E->getOperatorLoc(),
E->getOpcode(),
RHS.get(),
LHS.get());
}
ExprResult RebuildBinaryOperator(SourceLocation OpLoc, BinaryOperatorKind Opc, Expr* LHS, Expr* RHS) {
llvm::outs() << "-----------------------------" << "\n";
return SemaRef.BuildBinOp(SemaRef.getCurScope(), OpLoc, Opc, RHS, LHS);
}
};
class ASTVisitor : public RecursiveASTVisitor<ASTVisitor> {
clang::ASTContext& Context;
clang::Sema& SemaRef;
public:
public:
ASTVisitor(clang::ASTContext& Context, clang::Sema& SemaRef) : Context(Context), SemaRef(SemaRef) {}
bool VisitVarDecl(VarDecl* decl) {
llvm::outs() << "Visiting BinaryOperator\n";
clang::MyTreeTransform transformer{SemaRef, Context};
decl->dump();
auto result = transformer.TransformExpr(decl->getInit());
decl->setInit(result.get());
decl->dump();
return true;
}
};
class MySemaConsumer : public clang::SemaConsumer {
clang::CompilerInstance& CI;
public:
MySemaConsumer(clang::CompilerInstance& CI) : CI(CI) {}
void HandleTranslationUnit(clang::ASTContext& Context) override {
clang::Sema& SemaRef = CI.getSema();
clang::MyTreeTransform Transformer(SemaRef, Context);
llvm::outs() << "------------------------------\n";
auto TU = Context.getTranslationUnitDecl();
clang::ASTVisitor visitor{Context, SemaRef};
visitor.TraverseDecl(TU);
}
};
class MyFrontendAction : public clang::ASTFrontendAction {
public:
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance& CI,
llvm::StringRef) override {
return std::make_unique<MySemaConsumer>(CI);
}
};
} // namespace clang
int main(int argc, const char** argv) {
assert(argc == 2 && "Usage: Preprocessor <source-file>");
llvm::outs() << "running ASTVisitor...\n";
auto instance = std::make_unique<clang::CompilerInstance>();
clang::DiagnosticIDs* ids = new clang::DiagnosticIDs();
clang::DiagnosticOptions* diag_opts = new clang::DiagnosticOptions();
clang::DiagnosticConsumer* consumer = new clang::IgnoringDiagConsumer();
clang::DiagnosticsEngine* engine = new clang::DiagnosticsEngine(ids, diag_opts, consumer);
instance->setDiagnostics(engine);
auto invocation = std::make_shared<clang::CompilerInvocation>();
std::vector<const char*> args = {
"/usr/local/bin/clang++",
"-Xclang",
"-no-round-trip-args",
"-std=c++20",
argv[1],
};
invocation = clang::createInvocation(args, {});
// clang::CompilerInvocation::CreateFromArgs(*invocation, args, instance->getDiagnostics());
instance->setInvocation(std::move(invocation));
if(!instance->createTarget()) {
llvm::errs() << "Failed to create target\n";
std::terminate();
}
// instance->setASTConsumer(std::make_unique<clang::MyASTConsumer>(*instance));
clang::MyFrontendAction action;
if(!action.BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0])) {
llvm::errs() << "Failed to begin source file\n";
std::terminate();
}
if(auto error = action.Execute()) {
llvm::errs() << "Failed to execute action: " << error << "\n";
std::terminate();
}
auto tu = instance->getASTContext().getTranslationUnitDecl();
// tu->dump();
// ASTVistor visitor{instance->getPreprocessor(), buffer, instance->getASTContext(),
// instance->getSema()}; visitor.TraverseDecl(tu);
action.EndSourceFile();
};

View File

@@ -1,65 +0,0 @@
#pragma once
#include <Clang/Clang.h>
namespace clice {
class DependentShaper {
clang::ASTContext& context;
public:
DependentShaper(clang::ASTContext& context) : context(context) {}
const clang::NamedDecl* simplify(const clang::TemplateSpecializationType* templateType,
const clang::IdentifierInfo* identifier) {
// get the template decl of the template specialization
// e.g. vector<int> -> vector
// get the template arguments of the template specialization
// e.g. vector<int> -> int
auto templateDecl = templateType->getTemplateName().getAsTemplateDecl();
if(auto decl = llvm::dyn_cast<clang::ClassTemplateDecl>(templateDecl)) {
// get the record decl of the template decl
clang::CXXRecordDecl* recordDecl = decl->getTemplatedDecl();
// lookup the identifier in the record decl
auto result = recordDecl->lookup(identifier);
assert(result.size() == 1 && "multiple results found");
return result.front();
} else if(auto decl = llvm::dyn_cast<clang::TypeAliasTemplateDecl>(templateDecl)) {
}
}
const clang::NamedDecl* simplify(const clang::NestedNameSpecifier* specifier,
const clang::IdentifierInfo* identifier) {
switch(specifier->getKind()) {
case clang::NestedNameSpecifier::TypeSpec: {
auto node = specifier->getAsType();
if(auto type = node->getAs<clang::TemplateTypeParmType>()) {
// represent a direct dependent name, e.g. typename T::^ name
// and can not be further simplified
} else if(auto type = node->getAs<clang::TemplateSpecializationType>()) {
// represent a dependent name that is a template specialization
// e.g. typename vector<int>::^ name, and can be further simplified
return simplify(type, identifier);
}
break;
}
case clang::NestedNameSpecifier::TypeSpecWithTemplate: {
break;
}
default: {
}
}
}
const clang::NamedDecl* simplify(const clang::DependentNameType* type) {
return simplify(type->getQualifier(), type->getIdentifier());
}
};
} // namespace clice

View File

View File

@@ -20,14 +20,14 @@ public:
requires std::is_invocable_v<Fn>
async(Fn&& fn) : callback(std::forward<Fn>(fn)) {}
bool await_ready(this const async& self) noexcept { return false; }
bool await_ready() noexcept { return false; }
void await_suspend(this async& self, std::coroutine_handle<> handle) noexcept {
self.handle = handle;
self.req.data = &self;
void await_suspend(std::coroutine_handle<> handle) noexcept {
handle = handle;
req.data = this;
uv_queue_work(
uv_default_loop(),
&self.req,
&this->req,
[](uv_work_t* req) {
auto& self = *static_cast<async*>(req->data);
self.result = self.callback();
@@ -41,9 +41,9 @@ public:
});
}
decltype(auto) await_resume(this async& self) noexcept {
assert(self.result.has_value());
return std::move(*self.result);
decltype(auto) await_resume() noexcept {
// assert(self.result.has_value());
return std::move(*this->result);
}
};

View File

@@ -1,7 +1,8 @@
cmake -B build -G Ninja \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_BUILD_TYPE=Debug \
-DCLICE_TEST=ON \
-DCLICE_EXAMPLES=ON

5
scripts/clone.sh Executable file
View File

@@ -0,0 +1,5 @@
cd external
git clone https://github.com/google/googletest.git --depth=1
git clone https://github.com/nlohmann/json.git --depth=1
git clone https://github.com/libuv/libuv.git --depth=1
git clone https://github.com/gabime/spdlog.git --depth=1

View File

@@ -1,4 +1,5 @@
#include <Clang/Directive.h>
#include <vector>
namespace clice {
@@ -14,7 +15,8 @@ public:
clang::OptionalFileEntryRef File,
StringRef SearchPath,
StringRef RelativePath,
const clang::Module* Imported,
const clang::Module* SuggestedModule,
bool ModuleImported,
clang::SrcMgr::CharacteristicKind FileType) override {}
void moduleImport(clang::SourceLocation ImportLoc,

View File

@@ -107,7 +107,7 @@ public:
if(lastLocation != location) {
// if not, update the last location and find the token
lastLocation = location;
auto token = buffer.spelledTokenAt(location);
auto token = buffer.spelledTokenContaining(location);
if(token) {
// if there is a corresponding token, update the token
auto iter = tokenMap.find(token);