diff --git a/include/Index/SymbolSlab.h b/include/Index/SymbolSlab.h index b984332a..064bb5e8 100644 --- a/include/Index/SymbolSlab.h +++ b/include/Index/SymbolSlab.h @@ -7,19 +7,26 @@ namespace clice { class SymbolSlab { public: - CSIF index(clang::Sema& sema, clang::syntax::TokenBuffer& tokBuf); + SymbolSlab(clang::Sema& sema, clang::syntax::TokenBuffer& tokBuf) : sema(sema), tokBuf(tokBuf) {} - std::size_t lookup(const clang::Decl* decl); + CSIF index(); - SymbolSlab& addSymbol(const clang::Decl* decl); + std::size_t lookup(const clang::NamedDecl* decl); - SymbolSlab& addOccurrence(const clang::Decl* decl, proto::Range range, Role role); + SymbolSlab& addSymbol(const clang::NamedDecl* decl); - SymbolSlab& addOccurrence(int Kind, proto::Range range); + SymbolSlab& addOccurrence(const clang::NamedDecl* decl, clang::SourceLocation range, Role role); - SymbolSlab& addRelation(const clang::Decl* from, const clang::Decl* to, Role role); + SymbolSlab& addOccurrence(const clang::NamedDecl* decl, clang::SourceRange range, Role role); + + SymbolSlab& addOccurrence(int Kind, clang::SourceLocation location); + + SymbolSlab& addRelation(const clang::NamedDecl* from, const clang::NamedDecl* to, Role role); private: + clang::Sema& sema; + clang::syntax::TokenBuffer& tokBuf; + llvm::BumpPtrAllocator allocator; llvm::StringSaver saver{allocator}; diff --git a/src/Index/Index.cpp b/src/Index/Index.cpp index 73eff131..e9cdcdc4 100644 --- a/src/Index/Index.cpp +++ b/src/Index/Index.cpp @@ -11,38 +11,6 @@ public: SymbolCollector(SymbolSlab& slab, clang::ASTContext& context) : slab(slab), context(context), srcMgr(context.getSourceManager()) {} - bool TraverseDecl(clang::Decl* decl) { - /// `TranslationUnitDecl` has invalid location information. - /// So we process it separately. - if(llvm::isa_and_nonnull(decl)) { - return Base::TraverseDecl(decl); - } - - if(decl->isImplicit()) { - return true; - } - - slab.addSymbol(decl); - llvm::outs() << "------------------------------------------\n"; - decl->dump(); - - // TODO: generate SymbolID for every decl. - // Distinguish linkage, for no or internal linkage. - // For them, relation lookup is only occurred in current TU. - - return Base::TraverseDecl(decl); - } - - // FIXME: check DeclRefExpr, MemberExpr, etc. - - bool TraverseStmt(clang::Stmt* stmt) { - return Base::TraverseStmt(stmt); - } - - bool TraverseAttr(clang::Attr* attr) { - return Base::TraverseAttr(attr); - } - /// we don't care about the node without location information, so skip them. constexpr bool shouldWalkTypesOfTypeLocs [[gnu::const]] () { return false; @@ -101,18 +69,22 @@ public: } bool TraverseNestedNameSpecifierLoc(clang::NestedNameSpecifierLoc NNS) { - // TODO: use TemplateResolver here. + // FIXME: use TemplateResolver here. + auto range = NNS.getSourceRange(); auto range2 = NNS.getLocalSourceRange(); return Base::TraverseNestedNameSpecifierLoc(NNS); } +#define VISIT_DECL(name) bool Visit##name(const clang::name* decl) #define VISIT_TYOELOC(name) bool Visit##name(clang::name loc) // TODO: ... add occurrence and relation. VISIT_TYOELOC(BuiltinTypeLoc) { + // FIXME: .... + // possible multiple tokens, ... map them to BuiltinKind. auto range = loc.getSourceRange(); return true; } @@ -127,18 +99,20 @@ public: return true; } - VISIT_TYOELOC(ElaboratedTypeLoc) { - auto loc1 = loc.getElaboratedKeywordLoc(); - - auto line = srcMgr.getPresumedLineNumber(loc1); - auto column = srcMgr.getPresumedColumnNumber(loc1); + VISIT_TYOELOC(TypedefTypeLoc) { + auto range = loc.getSourceRange(); + return true; + } + bool VisitElaboratedTypeLoc(clang ::ElaboratedTypeLoc loc) { + // FIXME: check the keyword. + auto keywordLoc = loc.getElaboratedKeywordLoc(); switch(loc.getTypePtr()->getKeyword()) { case clang::ElaboratedTypeKeyword::Struct: case clang::ElaboratedTypeKeyword::Class: case clang::ElaboratedTypeKeyword::Union: case clang::ElaboratedTypeKeyword::Enum: { - slab.addOccurrence(BuiltinSymbolKind::elaborated_type_specifier, {line, column}); + slab.addOccurrence(BuiltinSymbolKind::elaborated_type_specifier, keywordLoc); } case clang::ElaboratedTypeKeyword::Typename: { @@ -148,39 +122,63 @@ public: case clang::ElaboratedTypeKeyword::Interface: { } }; - loc1.dump(srcMgr); - return true; - // render keyword. - } - - VISIT_TYOELOC(TypedefTypeLoc) { - auto range = loc.getSourceRange(); return true; } - VISIT_TYOELOC(TemplateSpecializationTypeLoc) { - // TODO: add Relation. + VISIT_DECL(NamedDecl) { + // Every NamedDecl has a name should have a symbol. + // FIXME: add linkage information. when find information for external linkage, + // We need to cross reference with other TUs. + slab.addSymbol(decl); - auto name = loc.getTypePtr()->getTemplateName().getUnderlying(); - auto decl = name.getAsTemplateDecl(); + // FIXME: For some declaration with relation, we need to resolve them separately. + // e.g. ClassTemplateSpecializationDecl <-> ClassTemplateDecl + return true; + } + + VISIT_DECL(ClassTemplateDecl) { + auto name = decl->getDeclName(); + return true; + } + + bool VisitTemplateSpecializationTypeLoc(clang::TemplateSpecializationTypeLoc loc) { + auto nameLoc = loc.getTemplateNameLoc(); + const clang::TemplateSpecializationType* TST = loc.getTypePtr(); + clang::TemplateName name = TST->getTemplateName(); + clang::TemplateDecl* decl = name.getAsTemplateDecl(); + + // FIXME: record relation. + + // For a template specialization type, the template name is possibly a ClassTemplateDecl or a + // TypeAliasTemplateDecl. if(auto CTD = llvm::dyn_cast(decl)) { - auto nameLoc = loc.getTemplateNameLoc(); - auto line = srcMgr.getPresumedLineNumber(nameLoc); - auto column = srcMgr.getPresumedColumnNumber(nameLoc); - proto::Range range = {line, column, line, static_cast(column + decl->getName().size())}; - - void* ptr = CTD; - clang::ClassTemplateSpecializationDecl* decl2 = - CTD->findSpecialization(loc.getTypePtr()->template_arguments(), ptr); - auto main = decl2->getSpecializedTemplateOrPartial(); - - if(main.is()) { - auto decl3 = main.get(); - slab.addOccurrence(decl3, range, Role::ExplicitInstantiation); - } else { - auto decl3 = main.get(); - slab.addOccurrence(decl3, range, Role::ExplicitInstantiation); + // Dependent types are all handled in `TraverseNestedNameSpecifierLoc`. + if(TST->isDependentType()) { + return true; } + + // For non dependent types, it must has been instantiated(implicit or explicit). + // Find instantiated decl for it, main, partial specialization, full specialization?. + void* pos; + if(auto spec = CTD->findSpecialization(TST->template_arguments(), pos)) { + // If it's not full(explicit) specialization, find the primary template. + if(!spec->isExplicitInstantiationOrSpecialization()) { + auto specialized = spec->getSpecializedTemplateOrPartial(); + if(auto CTD = specialized.dyn_cast()) { + slab.addOccurrence(CTD, nameLoc, Role::ImplicitInstantiation); + } else { + auto PSD = specialized.get(); + slab.addOccurrence(PSD, nameLoc, Role::ImplicitInstantiation); + } + } else { + // full specialization + slab.addOccurrence(spec, nameLoc, Role::ExplicitInstantiation); + } + } + } else if(auto TATD = llvm::dyn_cast(decl)) { + // Beacuse type alias template is not allowed to have partial and full specialization, + // So we do notin + slab.addOccurrence(TATD, nameLoc, Role::ExplicitInstantiation); } return true; } @@ -196,7 +194,7 @@ private: } // namespace -CSIF SymbolSlab::index(clang::Sema& sema, clang::syntax::TokenBuffer& tokBuf) { +CSIF SymbolSlab::index() { CSIF csif; SymbolCollector collector(*this, sema.getASTContext()); collector.TraverseAST(sema.getASTContext()); diff --git a/src/Index/SymbolSlab.cpp b/src/Index/SymbolSlab.cpp index b39f8ac4..9f299872 100644 --- a/src/Index/SymbolSlab.cpp +++ b/src/Index/SymbolSlab.cpp @@ -3,7 +3,7 @@ namespace clice { -std::size_t SymbolSlab::lookup(const clang::Decl* decl) { +std::size_t SymbolSlab::lookup(const clang::NamedDecl* decl) { auto iter = cache.find(decl); if(iter == cache.end()) { llvm::outs() << "SymbolSlab::lookup: decl not found\n"; @@ -12,7 +12,7 @@ std::size_t SymbolSlab::lookup(const clang::Decl* decl) { return iter->second; } -SymbolSlab& SymbolSlab::addSymbol(const clang::Decl* decl) { +SymbolSlab& SymbolSlab::addSymbol(const clang::NamedDecl* decl) { // Generate and save USR. llvm::SmallString<128> USR; clang::index::generateUSRForDecl(decl, USR); @@ -29,19 +29,31 @@ SymbolSlab& SymbolSlab::addSymbol(const clang::Decl* decl) { return *this; } -SymbolSlab& SymbolSlab::addOccurrence(const clang::Decl* decl, proto::Range range, Role role) { +SymbolSlab& SymbolSlab::addOccurrence(const clang::NamedDecl* decl, clang::SourceLocation range, Role role) { + auto& srcMgr = sema.getSourceManager(); auto ID = symbols[lookup(decl)].ID; - occurrences.emplace_back(Occurrence{ID, range, role}); + auto line = srcMgr.getPresumedLineNumber(range); + auto column = srcMgr.getPresumedColumnNumber(range); + occurrences.emplace_back(Occurrence{ID, line, column, line, column, role}); return *this; } -SymbolSlab& SymbolSlab::addOccurrence(int Kind, proto::Range range) { +SymbolSlab& SymbolSlab::addOccurrence(const clang::NamedDecl* decl, clang::SourceRange range, Role role) { + auto ID = symbols[lookup(decl)].ID; + auto& srcMgr = sema.getSourceManager(); + auto line = srcMgr.getPresumedLineNumber(range.getBegin()); + auto column = srcMgr.getPresumedColumnNumber(range.getBegin()); + occurrences.emplace_back(Occurrence{ID, line, column, line, column, role}); + return *this; +} + +SymbolSlab& SymbolSlab::addOccurrence(int Kind, clang::SourceLocation loc) { auto ID = SymbolID::fromKind(Kind); - occurrences.emplace_back(Occurrence{ID, range, Role::Reference}); + // occurrences.emplace_back(Occurrence{ID, range, Role::Reference}); return *this; } -SymbolSlab& SymbolSlab::addRelation(const clang::Decl* from, const clang::Decl* to, Role role) { +SymbolSlab& SymbolSlab::addRelation(const clang::NamedDecl* from, const clang::NamedDecl* to, Role role) { std::size_t index = lookup(from); SymbolID fromID = symbols[index].ID; SymbolID toID = symbols[lookup(to)].ID; diff --git a/tests/Index/Index.cpp b/tests/Index/Index.cpp index 0653d84e..7358ab1f 100644 --- a/tests/Index/Index.cpp +++ b/tests/Index/Index.cpp @@ -3,29 +3,27 @@ #include #include #include +#include "../Test.h" using namespace clice; +std::vector compileArgs = { + "clang++", + "-std=c++20", + "main.cpp", + "-resource-dir", + "/home/ykiko/C++/clice2/build/lib/clang/20", +}; TEST(clice, Index) { - std::vector compileArgs = { - "clang++", - "-std=c++20", - "main.cpp", - "-resource-dir", - "/home/ykiko/C++/clice2/build/lib/clang/20", - }; - const char* code = R"( -struct X { }; -struct X x; -)"; - - Compiler compiler("main.cpp", code, compileArgs); - compiler.buildAST(); - SymbolSlab slab; - auto csif = slab.index(compiler.sema(), compiler.tokBuf()); - auto value = json::serialize(csif); - std::error_code EC; - llvm::raw_fd_ostream fileStream("output.json", EC); - fileStream << value << "\n"; - llvm::outs() << value << "\n"; + foreachFile("Index", [](llvm::StringRef filepath, llvm::StringRef content) { + Compiler compiler("main.cpp", content, compileArgs); + compiler.buildAST(); + SymbolSlab slab(compiler.sema(), compiler.tokBuf()); + auto csif = slab.index(); + auto value = json::serialize(csif); + std::error_code EC; + llvm::raw_fd_ostream fileStream("output.json", EC); + fileStream << value << "\n"; + llvm::outs() << value << "\n"; + }); } diff --git a/tests/Source/Index/ClassTemplate.cpp b/tests/Source/Index/ClassTemplate.cpp new file mode 100644 index 00000000..411d1294 --- /dev/null +++ b/tests/Source/Index/ClassTemplate.cpp @@ -0,0 +1,17 @@ +template +struct X {}; + +template +struct X {}; + +template <> +struct X {}; + +X x; + +X x2; + +X x3; + +template <> +struct X;