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