#include "Compiler.h" #include "Resolver.h" #include "Support/Enum.h" #include "Support/FileSystem.h" #include "Utility.h" namespace clice { enum class RelationKinds : uint32_t { Invalid, Declaration, Definition, Reference, // Write Relation. Read, Write, Interface, Implementation, /// When target is a type definition of source, source is possible type or constructor. TypeDefinition, /// When target is a base class of source. Base, /// When target is a derived class of source. Derived, /// When target is a constructor of source. Constructor, /// When target is a destructor of source. Destructor, // When target is a caller of source. Caller, // When target is a callee of source. Callee, }; struct RelationKind : enum_type { using enum RelationKinds; using enum_type::enum_type; using enum_type::operator=; }; enum class OccurrenceKind { /// This occurrence directly corresponds to a unique source symbol. Source, /// This occurrence is a macro expansion. MacroExpansion, /// This occurrence is from `PseudoInstantiation` and may be not correct. PseudoInstantiation, /// This occurrence is from `ImplicitInstantiation` or `ExplicitInstantiation` of a template. Instantiation, }; template class SemanticVisitor : public clang::RecursiveASTVisitor> { public: using Base = clang::RecursiveASTVisitor; SemanticVisitor(Compiler& compiler, bool mainFileOnly = false) : sema(compiler.sema()), resolver(compiler.resolver()), srcMgr(compiler.srcMgr()), tokBuf(compiler.tokBuf()), mainFileOnly(mainFileOnly) {} public: public: consteval bool VisitImplicitInstantiation() { return true; } Derived& getDerived() { return static_cast(*this); } bool needFilter(clang::SourceLocation location) { return location.isInvalid() || (mainFileOnly && !srcMgr.isInMainFile(location)); } void dump(clang::SourceLocation loc) { auto location = srcMgr.getPresumedLoc(loc); llvm::SmallString<128> path; auto err = fs::real_path(location.getFilename(), path); llvm::outs() << path << ":" << location.getLine() << ":" << location.getColumn() << "\n"; } /// An occurrence directly corresponding to a symbol in source code. /// In most cases, a location just correspondings to unique decl. /// So a location will be just visited once. But in some other cases, /// a location may correspond to multiple decls. Note that we already /// filter some nodes with invalid location. /// /// Always uses spelling location if the original location is a macro location. void handleOccurrence(const clang::Decl* decl, clang::SourceLocation location, OccurrenceKind kind = OccurrenceKind::Source) {} /// Builtin type doesn't have corresponding decl. So we handle it separately. /// And it is possible that a builtin type is composed of multiple tokens. /// e.g. `unsigned long long`. void handleOccurrence(const clang::BuiltinType* type, clang::SourceRange range, OccurrenceKind kind = OccurrenceKind::Source) {} void handleOccurrence(clang::Attr* attr, clang::SourceRange range) {} /// Always uses expansion location if the original location is a macro location. void handleRelation(const clang::Decl* decl, RelationKind kind, clang::SourceRange range) { /// } public: /// ============================================================================ /// Declaration /// ============================================================================ TRAVERSE_DECL(Decl) { if(!llvm::isa(decl) && needFilter(decl->getLocation())) { return true; } decls.push_back(decl); auto result = Base::TraverseDecl(decl); decls.pop_back(); return result; } VISIT_DECL(NamespaceDecl) { /// `namespace Foo { }` /// ^~~~ definition getDerived().handleOccurrence(decl, decl->getLocation()); return true; } VISIT_DECL(NamespaceAliasDecl) { /// `namespace Foo = Bar` /// ^ ^~~~ reference /// ^~~~ definition getDerived().handleOccurrence(decl, decl->getLocation()); getDerived().handleOccurrence(decl->getNamespace(), decl->getTargetNameLoc()); return true; } VISIT_DECL(UsingDirectiveDecl) { /// `using namespace Foo` /// ^~~~~~~ reference getDerived().handleOccurrence(decl->getNominatedNamespace(), decl->getLocation()); return true; } VISIT_DECL(LabelDecl) { /// `label:` /// ^~~~ definition getDerived().handleOccurrence(decl, decl->getLocation()); return true; } VISIT_DECL(FieldDecl) { /// `int foo;` /// ^~~~ definition getDerived().handleOccurrence(decl, decl->getLocation()); return true; } VISIT_DECL(EnumConstantDecl) { /// `enum Foo { bar };` /// ^~~~ definition getDerived().handleOccurrence(decl, decl->getLocation()); return true; } VISIT_DECL(UsingDecl) { /// `using Foo::bar;` /// ^~~~ reference getDerived().handleOccurrence(decl, decl->getLocation()); /// FIXME: return true; } VISIT_DECL(BindingDecl) { /// `auto [a, b] = std::make_tuple(1, 2);` /// ^~~~ definition getDerived().handleOccurrence(decl, decl->getLocation()); return true; } VISIT_DECL(TemplateTypeParmDecl) { /// `template ` /// ^~~~ definition getDerived().handleOccurrence(decl, decl->getLocation()); return true; } VISIT_DECL(TemplateTemplateParmDecl) { /// `template