Basic index logic for ClassTemplateDecl.
This commit is contained in:
@@ -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};
|
||||
|
||||
|
||||
@@ -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<clang::TranslationUnitDecl>(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<clang::ClassTemplateDecl>(decl)) {
|
||||
auto nameLoc = loc.getTemplateNameLoc();
|
||||
auto line = srcMgr.getPresumedLineNumber(nameLoc);
|
||||
auto column = srcMgr.getPresumedColumnNumber(nameLoc);
|
||||
proto::Range range = {line, column, line, static_cast<proto::uinteger>(column + decl->getName().size())};
|
||||
|
||||
void* ptr = CTD;
|
||||
clang::ClassTemplateSpecializationDecl* decl2 =
|
||||
CTD->findSpecialization(loc.getTypePtr()->template_arguments(), ptr);
|
||||
auto main = decl2->getSpecializedTemplateOrPartial();
|
||||
|
||||
if(main.is<clang::ClassTemplateDecl*>()) {
|
||||
auto decl3 = main.get<clang::ClassTemplateDecl*>();
|
||||
slab.addOccurrence(decl3, range, Role::ExplicitInstantiation);
|
||||
} else {
|
||||
auto decl3 = main.get<clang::ClassTemplatePartialSpecializationDecl*>();
|
||||
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<clang::ClassTemplateDecl*>()) {
|
||||
slab.addOccurrence(CTD, nameLoc, Role::ImplicitInstantiation);
|
||||
} else {
|
||||
auto PSD = specialized.get<clang::ClassTemplatePartialSpecializationDecl*>();
|
||||
slab.addOccurrence(PSD, nameLoc, Role::ImplicitInstantiation);
|
||||
}
|
||||
} else {
|
||||
// full specialization
|
||||
slab.addOccurrence(spec, nameLoc, Role::ExplicitInstantiation);
|
||||
}
|
||||
}
|
||||
} else if(auto TATD = llvm::dyn_cast<clang::TypeAliasTemplateDecl>(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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -3,29 +3,27 @@
|
||||
#include <Support/JSON.h>
|
||||
#include <Compiler/Compiler.h>
|
||||
#include <Support/FileSystem.h>
|
||||
#include "../Test.h"
|
||||
|
||||
using namespace clice;
|
||||
std::vector<const char*> compileArgs = {
|
||||
"clang++",
|
||||
"-std=c++20",
|
||||
"main.cpp",
|
||||
"-resource-dir",
|
||||
"/home/ykiko/C++/clice2/build/lib/clang/20",
|
||||
};
|
||||
|
||||
TEST(clice, Index) {
|
||||
std::vector<const char*> 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";
|
||||
});
|
||||
}
|
||||
|
||||
17
tests/Source/Index/ClassTemplate.cpp
Normal file
17
tests/Source/Index/ClassTemplate.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
template <typename T, typename U>
|
||||
struct X {};
|
||||
|
||||
template <typename T>
|
||||
struct X<T, T> {};
|
||||
|
||||
template <>
|
||||
struct X<int, int> {};
|
||||
|
||||
X<int, char> x;
|
||||
|
||||
X<char, char> x2;
|
||||
|
||||
X<int, int> x3;
|
||||
|
||||
template <>
|
||||
struct X<double, char>;
|
||||
Reference in New Issue
Block a user