diff --git a/.vscode/launch.json b/.vscode/launch.json index d91ebaae..0df4d8a7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -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}" }, diff --git a/CMakeLists.txt b/CMakeLists.txt index e7821c6b..5968692f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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() \ No newline at end of file diff --git a/docs/clangd.md b/docs/clangd.md index d08e9fbd..f219b556 100644 --- a/docs/clangd.md +++ b/docs/clangd.md @@ -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: 寻找核心优化点 diff --git a/docs/clice.md b/docs/clice.md index 9b0c5281..2a4ab003 100644 --- a/docs/clice.md +++ b/docs/clice.md @@ -77,4 +77,35 @@ 2. Semantic Tokens 等基于当前 AST 的操作,则是遍历 AST 渲染 Token 即可。 3. 剩下很多的,例如 Find References 等等等查询功能,都是在已经索引好的文件中进行查询,不需要对语法树进行什么改动。 -### \ No newline at end of file +### DependentNameResolver + +对于一个`DependentNameType`我们要分情况处理 + +最一般的`DependentNameType`可以用如下形式的正则表达式处理 `typename T<...>[::T2|::template T2<...>]*` + +首先我们要讨论希望化简到什么结果,例如对于 + +```cpp +typename std::vector>::reference +``` + +我们希望得到 + +```cpp +std::vector& +``` + +对于 + +```cpp +typename std::vector>::value_type::reference +``` + +我们希望得到 + +```cpp +T& +``` + +无论如何我们需要递归进行处理 + diff --git a/docs/examples/ASTVisitor.cpp b/docs/examples/ASTVisitor.cpp index 1e7035b1..80f7f359 100644 --- a/docs/examples/ASTVisitor.cpp +++ b/docs/examples/ASTVisitor.cpp @@ -1,5 +1,6 @@ #include #include +#include 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(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 resolve(llvm::ArrayRef arguments) { + std::vector result; + for(auto arg: arguments) { + if(arg.getKind() == TemplateArgument::ArgKind::Type) { + if(auto type = llvm::dyn_cast(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()) { + T = resolve(DNT); + } else if(auto DTST = T->getAs()) { + T = resolve(DTST); + } else if(auto LRT = T->getAs()) { + return Ctx.getLValueReferenceType(resolve(LRT->getPointeeType())); + } else { + return T; + } + } + } + + /// resolve a dependent name type, e.g. `typename std::vector::reference` + QualType resolve(const DependentNameType* DNT) { + // e.g. when DNT is `typename std::vector::reference` + // - qualifier: std::vector + // - 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::template rebind_alloc`. + // - qualifier: std::allocator_traits + // - identifier: rebind_alloc + // - template_arguments: + return resolve(DTST->getQualifier(), DTST->getIdentifier(), DTST->template_arguments()); + } + + QualType resolve(const NestedNameSpecifier* TST, + const IdentifierInfo* II, + ArrayRef arguments = {}) { + + switch(TST->getKind()) { + case NestedNameSpecifier::SpecifierKind::Identifier: { + llvm::outs() << "\n------------------ Identifier -----------------------\n"; + // when the kind of TST is Identifier + // e.g. std::vector>::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:: + 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::template name:: + 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 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(member)) { + type = TAD->getUnderlyingType(); + } else if(auto TD = llvm::dyn_cast(member)) { + type = TD->getUnderlyingType(); + } else if(auto TATD = llvm::dyn_cast(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(member)) { + return substitute(CTD, II, arguments); + } else { + member->dump(); + std::terminate(); + } + + list.addOuterTemplateArguments(CTD, args, true); + return S.SubstType(type, list, {}, {}); + } + + /// typename A::template B::template C::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 arguments = {}) { + if(!T->isDependentType() && arguments.size() == 0) { + // TODO: + } + llvm::outs() << "\n"; + T.dump(); + Sema::CodeSynthesisContext context; + + if(auto TTPT = T->getAs()) { + 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()) { + auto TemplateName = TST->getTemplateName(); + auto TemplateDecl = TemplateName.getAsTemplateDecl(); + auto TemplatedDecl = TemplateDecl->getTemplatedDecl(); + + if(auto CTD = llvm::dyn_cast(TemplateDecl)) { + return substitute(CTD, II, TST->template_arguments()); + } else { + TemplateDecl->dump(); + std::terminate(); + } + auto TemplateArgs = TST->template_arguments(); + } else if(auto DTST = T->getAs()) { + auto TST = DTST->getQualifier()->getAsType()->getAs(); + auto TemplateName = TST->getTemplateName(); + auto TemplateDecl = TemplateName.getAsTemplateDecl(); + auto TemplatedDecl = TemplateDecl->getTemplatedDecl(); + + if(auto CTD = llvm::dyn_cast(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(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(CRD->lookup(II).front())->getUnderlyingType(), + list, + {}, + {}); + + } else if(auto TATD = llvm::dyn_cast(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>*> arguments; + +public: + DependentNameResolverV2(ASTContext& Ctx, Sema& S) : Ctx(Ctx), S(S) {} + + std::vector resolve(llvm::ArrayRef arguments) { + std::vector result; + for(auto arg: arguments) { + if(arg.getKind() == TemplateArgument::ArgKind::Type) { + if(auto type = llvm::dyn_cast(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()) { + return QualType(DNT, 0); + } else if(auto DTST = type->getAs()) { + 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()) { + 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()) { + auto ND = resolve(DTST->getQualifier(), DTST->getIdentifier()); + if(auto TATD = llvm::dyn_cast(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()) { + type = Ctx.getLValueReferenceType(resolve(LRT->getPointeeType())); + } else { + return type; + } + } + } + + QualType resolve(NamedDecl* ND) { + if(auto TD = llvm::dyn_cast(ND)) { + return TD->getUnderlyingType(); + } else if(auto TAD = llvm::dyn_cast(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 arguments; + + llvm::outs() << "--------------------------------------------------------------------\n"; + Type.dump(); + + if(auto TTPT = Type->getAs()) { + Type->dump(); + std::terminate(); + } else if(auto TST = Type->getAs()) { + auto TemplateName = TST->getTemplateName(); + TemplateDecl = TemplateName.getAsTemplateDecl(); + arguments = TST->template_arguments(); + } else if(auto DTST = Type->getAs()) { + TemplateDecl = resolve(DTST->getQualifier(), DTST->getIdentifier()); + arguments = DTST->template_arguments(); + } else if(auto RT = Type->getAs()) { + return RT->getDecl()->lookup(Name).front(); + } else { + Type->dump(); + std::terminate(); + } + + this->arguments.push_back( + new std::pair>{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(TemplateDecl)) { + llvm::outs() << "--------------------------------------------------------------------\n"; + llvm::SmallVector 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(TemplateDecl)) { + result = lookup(TATD->getTemplatedDecl()->getUnderlyingType(), Name); + } + + if(result == nullptr) { + Type.dump(); + std::terminate(); + } + + return result; + } +}; + +} // namespace clang + class ASTVistor : public clang::RecursiveASTVisitor { 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()) { - 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(); std::vector args = { - "/home/ykiko/Project/C++/clice/external/llvm/bin/clang++", + "/usr/local/bin/clang++", "-Xclang", "-no-round-trip-args", "-std=c++20", diff --git a/docs/examples/CodeCompletion.cpp b/docs/examples/CodeCompletion.cpp index e98fad8f..d9eade4e 100644 --- a/docs/examples/CodeCompletion.cpp +++ b/docs/examples/CodeCompletion.cpp @@ -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()) { - auto qualifers = dependentType->getQualifier(); - // qualifers->getKind() -> clang::NestedNameSpecifier::SpecifierKind; - // auto t = qualifers->getAsType(); - // TODO: 看是否能根据主模板一路把依赖名替换下去,直到变成非依赖名 - } else if(const auto dependentType = type->getAs()) { - } - } - 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()) { + // auto qualifers = dependentType->getQualifier(); + // // qualifers->getKind() -> clang::NestedNameSpecifier::SpecifierKind; + // // auto t = qualifers->getAsType(); + // // TODO: 看是否能根据主模板一路把依赖名替换下去,直到变成非依赖名 + // } else if(const auto dependentType = type->getAs()) { + // } + // } + // 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(); std::vector args = { - "/home/ykiko/Project/C++/clice/external/llvm/bin/clang++", + "/usr/local/bin/clang++", "-Xclang", "-no-round-trip-args", "-std=c++20", diff --git a/docs/examples/TreeTransform.cpp b/docs/examples/TreeTransform.cpp new file mode 100644 index 00000000..8e84e880 --- /dev/null +++ b/docs/examples/TreeTransform.cpp @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include + +namespace clang { +class MyTreeTransform : public TreeTransform { + ASTContext& Context; + +public: + MyTreeTransform(Sema& SemaRef, clang::ASTContext& Context) : + TreeTransform(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 { + 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 CreateASTConsumer(clang::CompilerInstance& CI, + llvm::StringRef) override { + return std::make_unique(CI); + } +}; + +} // namespace clang + +int main(int argc, const char** argv) { + assert(argc == 2 && "Usage: Preprocessor "); + llvm::outs() << "running ASTVisitor...\n"; + + auto instance = std::make_unique(); + + 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(); + std::vector 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(*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(); +}; diff --git a/include/Clang/DependentShaper.h b/include/Clang/DependentShaper.h deleted file mode 100644 index d1c34736..00000000 --- a/include/Clang/DependentShaper.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include - -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 -> vector - - // get the template arguments of the template specialization - // e.g. vector -> int - auto templateDecl = templateType->getTemplateName().getAsTemplateDecl(); - if(auto decl = llvm::dyn_cast(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(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()) { - // represent a direct dependent name, e.g. typename T::^ name - // and can not be further simplified - } else if(auto type = node->getAs()) { - // represent a dependent name that is a template specialization - // e.g. typename vector::^ 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 diff --git a/include/Clang/SelectionTree.h b/include/Clang/SelectionTree.h new file mode 100644 index 00000000..e69de29b diff --git a/include/Support/Async.h b/include/Support/Async.h index 9ce65467..f191ee20 100644 --- a/include/Support/Async.h +++ b/include/Support/Async.h @@ -20,14 +20,14 @@ public: requires std::is_invocable_v async(Fn&& fn) : callback(std::forward(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(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); } }; diff --git a/scripts/build.sh b/scripts/build.sh index da180d78..a9acba54 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -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 diff --git a/scripts/clone.sh b/scripts/clone.sh new file mode 100755 index 00000000..88c63a90 --- /dev/null +++ b/scripts/clone.sh @@ -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 \ No newline at end of file diff --git a/src/Clang/Directive.cpp b/src/Clang/Directive.cpp index bc974434..1037da68 100644 --- a/src/Clang/Directive.cpp +++ b/src/Clang/Directive.cpp @@ -1,4 +1,5 @@ #include +#include 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, diff --git a/src/Feature/SemanticToken.cpp b/src/Feature/SemanticToken.cpp index e88ea0f9..c5d67abc 100644 --- a/src/Feature/SemanticToken.cpp +++ b/src/Feature/SemanticToken.cpp @@ -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);