File indexing completed on 2024-05-19 05:42:03

0001 // ct_lvtclp_logicaldepvisitor.h                                      -*-C++-*-
0002 
0003 /*
0004 // Copyright 2023 Codethink Ltd <codethink@codethink.co.uk>
0005 // SPDX-License-Identifier: Apache-2.0
0006 //
0007 // Licensed under the Apache License, Version 2.0 (the "License");
0008 // you may not use this file except in compliance with the License.
0009 // You may obtain a copy of the License at
0010 //
0011 //     http://www.apache.org/licenses/LICENSE-2.0
0012 //
0013 // Unless required by applicable law or agreed to in writing, software
0014 // distributed under the License is distributed on an "AS IS" BASIS,
0015 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0016 // See the License for the specific language governing permissions and
0017 // limitations under the License.
0018 */
0019 
0020 #ifndef INCLUDED_CT_LVTCLP_LOGICALDEPVISITOR
0021 #define INCLUDED_CT_LVTCLP_LOGICALDEPVISITOR
0022 
0023 //@PURPOSE: Provides callbacks invoked by clang when traversing its AST
0024 //
0025 //@CLASSES:
0026 //  lvtclp::LogicalDepVistor Implements clang::RecursiveASTVisitor
0027 //                           Not for use outside lvtclp
0028 //
0029 //@SEE_ALSO:
0030 //
0031 //@DESCRIPTION:
0032 // See https://clang.llvm.org/docs/RAVFrontendAction.html
0033 //
0034 // clang::RecursiveASTVisitor provides callbacks for types of nodes in clang's
0035 // abstract syntax tree representation of a C++ source file. Our callbacks
0036 // add these nodes to the code database
0037 
0038 #include <ct_lvtclp_clputil.h>
0039 #include <ct_lvtclp_staticfnhandler.h>
0040 #include <ct_lvtclp_visitlog.h>
0041 
0042 #include <ct_lvtshr_graphenums.h>
0043 
0044 #include <clang/AST/AST.h>
0045 #include <clang/AST/RecursiveASTVisitor.h>
0046 #include <clang/Basic/SourceLocation.h>
0047 #include <clang/Frontend/ASTConsumers.h>
0048 
0049 #include <filesystem>
0050 #include <functional>
0051 #include <memory>
0052 #include <string>
0053 #include <vector>
0054 
0055 namespace Codethink {
0056 
0057 namespace lvtmdb {
0058 class FieldObject;
0059 }
0060 namespace lvtmdb {
0061 class FileObject;
0062 }
0063 namespace lvtmdb {
0064 class MethodObject;
0065 }
0066 namespace lvtmdb {
0067 class NamespaceObject;
0068 }
0069 namespace lvtmdb {
0070 class ObjectStore;
0071 }
0072 namespace lvtmdb {
0073 class PackageObject;
0074 }
0075 namespace lvtmdb {
0076 class TypeObject;
0077 }
0078 
0079 namespace lvtclp {
0080 
0081 // =======================
0082 // class LogicalDepVisitor
0083 // =======================
0084 
0085 class LogicalDepVisitor : public clang::RecursiveASTVisitor<LogicalDepVisitor> {
0086     // Implements RecursiveASTVisitor and specifies which AST nodes it is
0087     // interested in by overriding the relevant methods. These methods are
0088     // invoked as nodes of that type are encountered in the AST. For example,
0089     // VistNamespaceDecl is invoked for each namespace declaration. These methods
0090     // then add the relevant data to the database.
0091 
0092     // DATA
0093     clang::ASTContext *Context;
0094     // Holds long-lived AST nodes (such as types and decls) that can be
0095     // referred to throughout the semantic analysis of a file
0096 
0097     lvtmdb::FileObject *sourceFilePtr;
0098     // The database row representing the source file of the translation unit
0099 
0100     lvtmdb::ObjectStore& d_memDb;
0101     // The active database session to add objects to
0102 
0103     std::filesystem::path d_prefix;
0104 
0105     std::vector<std::filesystem::path> d_nonLakosianDirs;
0106     std::vector<std::pair<std::string, std::string>> d_thirdPartyDirs;
0107 
0108     std::shared_ptr<VisitLog> d_visitLog_p;
0109 
0110     std::shared_ptr<StaticFnHandler> d_staticFnHandler_p;
0111 
0112     std::optional<std::function<void(const std::string&, long)>> d_messageCallback;
0113 
0114     bool d_catchCodeAnalysisOutput;
0115 
0116     // MANIPULATORS
0117     static const clang::CXXRecordDecl *qualTypeToRecordDecl(clang::QualType qualType);
0118     // Converts a QualType to an underlying C++ class type. If the QualType
0119     // has no underlying C++ class, it returns nullptr.
0120 
0121     void processMethodArg(const clang::VarDecl *varDecl,
0122                           lvtmdb::TypeObject *containerDecl,
0123                           clang::AccessSpecifier access = clang::AS_none);
0124     // If the appropriate access specifier is not known, leave it as AS_none,
0125     // and it can be figured out for normal method arguments or for lambda
0126     // arguments for a lambda declared inside a method
0127 
0128     void writeMethodArgRelation(const clang::Decl *decl,
0129                                 clang::QualType type,
0130                                 clang::AccessSpecifier access,
0131                                 lvtmdb::TypeObject *parentClassPtr,
0132                                 lvtmdb::MethodObject *methodDeclarationPtr);
0133     // Writes relations for the class in 'declPtr' for
0134     // where it is used as an argument type in a method in the parent class
0135 
0136     void parseArgumentTemplate(const clang::Decl *decl,
0137                                const clang::TemplateSpecializationType *templateTypePtr,
0138                                clang::AccessSpecifier access,
0139                                lvtmdb::TypeObject *parentClassPtr,
0140                                lvtmdb::MethodObject *methodDeclarationPtr);
0141     // Decompose a template type into its components
0142 
0143     void writeFieldRelations(const clang::Decl *decl,
0144                              clang::QualType fieldClass,
0145                              lvtmdb::TypeObject *parentClassPtr,
0146                              lvtmdb::FieldObject *fieldDeclarationPtr);
0147     // Writes appropriate relations for the class in 'declPtr'
0148     // for where it is used as a type in a field in the parent class
0149 
0150     void parseFieldTemplate(const clang::Decl *decl,
0151                             const clang::TemplateSpecializationType *templateTypePtr,
0152                             lvtmdb::TypeObject *parentClassPtr,
0153                             lvtmdb::FieldObject *fieldDeclarationPtr);
0154     // Write UsesInTheImplementation relations for the component types of the
0155     // templateTypePtr
0156 
0157     void visitLocalVarDeclOrParam(clang::VarDecl *varDecl);
0158     // Visit a variable declaration inside a function/method
0159 
0160     std::string getSignature(const clang::FunctionDecl *functionDecl);
0161     // Obtains the type signature for a function as a string
0162 
0163     void processBaseClassTemplateArgs(const clang::Decl *decl,
0164                                       lvtmdb::TypeObject *parent,
0165                                       const clang::CXXRecordDecl::base_class_range& bases);
0166     // Add uses in the interface relations for any template arguments to
0167     // base classes
0168 
0169     void addField(lvtmdb::TypeObject *parent, const clang::ValueDecl *decl, bool isStatic);
0170     // Add a field (described by `decl`) inside `parent` to the database
0171 
0172     std::vector<lvtmdb::TypeObject *>
0173     getTemplateArguments(clang::QualType type, const clang::Decl *decl, const char *desc);
0174     // Gets template arguments of type (if any)
0175 
0176     void addRelation(lvtmdb::TypeObject *source,
0177                      clang::QualType targetType,
0178                      const clang::Decl *decl,
0179                      clang::AccessSpecifier access,
0180                      const char *desc);
0181     // (Preferred version)
0182     // Add a relationship between source and target, choosing usesInImpl or
0183     // usesInInterface depending on the access specifier. decl and desc are
0184     // used to print a message using debugRelationship() when debugging is
0185     // enabled
0186     // Adds appropriate relationships for any template args of targetType
0187 
0188     void addRelation(lvtmdb::TypeObject *source,
0189                      lvtmdb::TypeObject *target,
0190                      const clang::Decl *decl,
0191                      clang::AccessSpecifier access,
0192                      const char *desc);
0193     // (Overload only for when the QualType of target is unavailable)
0194     // Add a relationship between source and target, choosing usesInImpl or
0195     // usesInInterface depending on the access specifier. decl and desc are
0196     // used to print a message using debugRelationship() when debugging is
0197     // enabled
0198 
0199     static void debugRelationship(
0200         lvtmdb::TypeObject *source, lvtmdb::TypeObject *target, const clang::Decl *decl, bool impl, const char *desc);
0201 
0202     static bool funcIsTemplateSpecialization(const clang::FunctionDecl *decl);
0203     static bool classIsTemplateSpecialization(const clang::CXXRecordDecl *decl);
0204     static bool methodIsTemplateSpecialization(const clang::CXXMethodDecl *decl);
0205 
0206     static bool skipRecord(const clang::CXXRecordDecl *recordDecl);
0207     // Determine whether this is a record which should/might be added to the
0208     // database
0209 
0210     lvtmdb::TypeObject *lookupUDT(const clang::NamedDecl *decl, const char *warnMsg);
0211     // Look up a UDT possibly already in the database. If not found return
0212     // a nullptr.
0213     // If warnMsg is non-null, print a warning when the class lookup fails.
0214 
0215     lvtmdb::TypeObject *lookupParentRecord(const clang::CXXRecordDecl *record, const char *warnMsg);
0216     // Like lookupRecord() except this will also resolve lambdas to their
0217     // containing class (and lambdas-in-lambdas, etc). This is useful for
0218     // finding the "real" class which should be used in a relation
0219 
0220     lvtmdb::TypeObject *
0221     lookupType(const clang::Decl *decl, clang::QualType qualType, const char *warnMsg, bool resolveParent);
0222 
0223     std::string getReturnType(const clang::FunctionDecl *fnDecl);
0224     // Get a normalized return type for a function
0225 
0226     void processChildStatements(const clang::Decl *decl, const clang::Stmt *top, lvtmdb::TypeObject *parent);
0227     // Search statements recursively from top for any relations we need to
0228     // add for parentDecl.
0229 
0230     std::vector<lvtmdb::TypeObject *>
0231     listChildStatementRelations(const clang::Decl *decl, const clang::Stmt *top, lvtmdb::TypeObject *parent);
0232     // Like processChildStatements except the uses-in-the-implementation
0233     // relations are listed in a vector instead of added
0234 
0235     void addReturnRelation(const clang::FunctionDecl *func, lvtmdb::TypeObject *parent, clang::AccessSpecifier access);
0236     // Adds a relation from parent for func's return value, according to the
0237     // access specifier. If parent is a lambda, a relation will be added from
0238     // parent's parent, etc.
0239 
0240     void parseReturnTemplate(const clang::Decl *decl,
0241                              clang::QualType returnQType,
0242                              lvtmdb::TypeObject *parent,
0243                              clang::AccessSpecifier access);
0244     // Recursively parse and add relations for a templated return type.
0245     // If this is a non-templated type, the relation will be added.
0246 
0247     void addUDTSourceFile(lvtmdb::TypeObject *udt, const clang::Decl *decl);
0248     // Add the location of the decl to the source files for that UDT
0249 
0250     lvtmdb::TypeObject *addUDT(const clang::NamedDecl *nameDecl, lvtshr::UDTKind kind);
0251     // Adds a clang::NamedDecl to the database as a user defined type
0252 
0253     void visitTypeAlias(const clang::NamedDecl *nameDecl, clang::QualType referencedType);
0254     // Process some kind of type alias described by nameDecl. The underlying
0255     // type referred to by the new name is referencedType
0256 
0257     static std::string getTemplateParameters(const clang::FunctionDecl *functionDecl);
0258     // Format the template parameters (if present) is a function decl
0259 
0260   public:
0261     // CREATORS
0262     LogicalDepVisitor(clang::ASTContext *context,
0263                       clang::StringRef file,
0264                       lvtmdb::ObjectStore& memDb,
0265                       std::filesystem::path prefix,
0266                       std::vector<std::filesystem::path> nonLakosians,
0267                       std::vector<std::pair<std::string, std::string>> d_thirdPartyDirs,
0268                       std::shared_ptr<VisitLog> visitLog,
0269                       std::shared_ptr<StaticFnHandler> staticFnHandler,
0270                       std::optional<std::function<void(const std::string&, long)>> d_messageCallback,
0271                       bool catchCodeAnalysisOutput);
0272     // Instantiate a new LogicalDepVisitor for the given file as a
0273     // translation unit
0274 
0275     bool VisitNamespaceDecl(clang::NamespaceDecl *namespaceDecl);
0276     // Extract data about the namespace hierarchy
0277 
0278     bool VisitCXXRecordDecl(clang::CXXRecordDecl *recordDecl);
0279     // Extract data about the C++ classes
0280 
0281     bool VisitFunctionDecl(clang::FunctionDecl *functionDecl);
0282     // Extract data about C++ static and member functions and stand along
0283     // functions within namespaces
0284 
0285     bool VisitFieldDecl(clang::FieldDecl *fieldDecl);
0286     // Extract data about the fields within a class
0287 
0288     bool VisitVarDecl(clang::VarDecl *varDecl);
0289     // Extract data about the variable declarations
0290 
0291     bool VisitCXXMethodDecl(clang::CXXMethodDecl *methodDecl);
0292     // Scan through each method for temporary objects (which imply usesInImpl)
0293 
0294     bool VisitUsingDecl(clang::UsingDecl *usingDecl);
0295     // Kind of a type alias e.g.
0296     // namespace foo { class C; }
0297     // namespace bar { using foo::C; }
0298     // bar::C === foo::C
0299 
0300     bool VisitTypedefNameDecl(clang::TypedefNameDecl *nameDecl);
0301     // Visit type aliases (e.g. using foo = bar;)
0302     // and typedefs
0303 
0304     bool VisitEnumDecl(clang::EnumDecl *enumDecl);
0305     // Extract data about enums (scoped or not)
0306 };
0307 
0308 } // namespace lvtclp
0309 
0310 } // namespace Codethink
0311 
0312 #endif