File indexing completed on 2024-05-19 05:42:02
0001 // ct_lvtclp_logicaldepscanner.cpp -*-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 #include <ct_lvtclp_logicaldepscanner.h> 0021 #include <ct_lvtclp_logicaldepvisitor.h> 0022 0023 #include <ct_lvtclp_staticfnhandler.h> 0024 #include <ct_lvtclp_visitlog.h> 0025 0026 #include <clang/AST/ASTConsumer.h> 0027 #include <clang/Frontend/CompilerInstance.h> 0028 #include <clang/Frontend/FrontendActions.h> 0029 0030 #include <ct_lvtclp_diagnostic_consumer.h> 0031 0032 #include <filesystem> 0033 0034 namespace { 0035 0036 using namespace Codethink; 0037 using namespace lvtclp; 0038 0039 // ======================== 0040 // class LogicalDepConsumer 0041 // ======================== 0042 0043 class LogicalDepConsumer : public clang::ASTConsumer { 0044 // Implementation of the ASTConsumer interface for reading an AST produced 0045 // by the Clang parser. Each instance is specific to a file. 0046 0047 // DATA 0048 LogicalDepVisitor d_visitor; 0049 // LogicalDepVisitor which inspects AST nodes 0050 0051 std::optional<std::function<void(const std::string&, long)>> d_messageCallback; 0052 // sends a message to the UI. 0053 0054 std::optional<HandleCppCommentsCallback_f> d_handleCppCommentsCallback; 0055 0056 std::string d_filename; 0057 clang::ASTContext *d_context; 0058 0059 public: 0060 // CREATORS 0061 LogicalDepConsumer(clang::ASTContext *context, 0062 clang::StringRef file, 0063 lvtmdb::ObjectStore& memDb, 0064 const std::filesystem::path& prefix, 0065 const std::vector<std::filesystem::path>& nonLakosians, 0066 std::vector<std::pair<std::string, std::string>> d_thirdPartyDirs, 0067 const std::shared_ptr<VisitLog>& visitLog, 0068 const std::shared_ptr<StaticFnHandler>& staticFnHandler, 0069 std::optional<std::function<void(const std::string&, long)>> messageCallback, 0070 bool catchCodeAnalysisOutput, 0071 std::optional<HandleCppCommentsCallback_f> handleCppCommentsCallback = std::nullopt): 0072 0073 // Instantiates a new LogicalDepConsumer for the given file as a 0074 // translation unit 0075 d_visitor(context, 0076 file, 0077 memDb, 0078 prefix, 0079 nonLakosians, 0080 std::move(d_thirdPartyDirs), 0081 visitLog, 0082 staticFnHandler, 0083 std::move(messageCallback), 0084 catchCodeAnalysisOutput), 0085 d_handleCppCommentsCallback(std::move(handleCppCommentsCallback)), 0086 d_filename(file.str()), 0087 d_context(context) 0088 { 0089 } 0090 0091 // MANIPULATORS 0092 bool HandleTopLevelDecl(clang::DeclGroupRef declGroupRef) override 0093 // Override the method that gets called for each parsed top-level 0094 // declaration 0095 { 0096 if (d_handleCppCommentsCallback) { 0097 auto& ctx = *d_context; 0098 auto& sm = ctx.getSourceManager(); 0099 auto *commentsInFile = ctx.Comments.getCommentsInFile(sm.getMainFileID()); 0100 if (commentsInFile) { 0101 for (auto&& [_, rawComment] : *commentsInFile) { 0102 auto filename = std::filesystem::path{d_filename}.filename().string(); 0103 auto briefText = rawComment->getBriefText(ctx); 0104 auto startLine = sm.getExpansionLineNumber(rawComment->getBeginLoc()); 0105 auto endLine = sm.getExpansionLineNumber(rawComment->getEndLoc()); 0106 (*d_handleCppCommentsCallback)(filename, briefText, startLine, endLine); 0107 } 0108 } 0109 } 0110 0111 for (auto *b : declGroupRef) { 0112 // Traverse the declaration using our AST visitor. 0113 d_visitor.TraverseDecl(b); 0114 } 0115 0116 return true; 0117 } 0118 }; 0119 0120 // ============================== 0121 // class LogicalDepFrontendAction 0122 // ============================== 0123 0124 class LogicalDepFrontendAction : public clang::SyntaxOnlyAction { 0125 // Per-thread clang tooling stuff 0126 0127 // DATA 0128 lvtmdb::ObjectStore& d_memDb; 0129 0130 std::filesystem::path d_prefix; 0131 0132 std::vector<std::filesystem::path> d_nonLakosianDirs; 0133 std::vector<std::pair<std::string, std::string>> d_thirdPartyDirs; 0134 0135 std::shared_ptr<VisitLog> d_visitLog_p; 0136 std::shared_ptr<StaticFnHandler> d_staticFnHandler_p; 0137 0138 std::function<void(const std::string&)> d_filenameCallback; 0139 // callback when we process a new file 0140 0141 std::optional<std::function<void(const std::string&, long)>> d_messageCallback; 0142 // sends a message to the UI. 0143 0144 bool d_catchCodeAnalysisOutput; 0145 0146 std::optional<HandleCppCommentsCallback_f> d_handleCppCommentsCallback; 0147 0148 public: 0149 // CREATORS 0150 LogicalDepFrontendAction(lvtmdb::ObjectStore& memDb, 0151 std::filesystem::path prefix, 0152 std::vector<std::filesystem::path> nonLakosians, 0153 std::vector<std::pair<std::string, std::string>> thirdPartyDirs, 0154 std::function<void(const std::string&)> filenameCallback, 0155 std::optional<std::function<void(const std::string&, long)>> messageCallback, 0156 bool catchCodeAnalysisOutput, 0157 std::optional<HandleCppCommentsCallback_f> handleCppCommentsCallback = std::nullopt): 0158 d_memDb(memDb), 0159 d_prefix(std::move(prefix)), 0160 d_nonLakosianDirs(std::move(nonLakosians)), 0161 d_thirdPartyDirs(std::move(thirdPartyDirs)), 0162 d_visitLog_p(std::make_shared<VisitLog>()), 0163 d_staticFnHandler_p(std::make_shared<StaticFnHandler>(memDb)), 0164 d_filenameCallback(std::move(filenameCallback)), 0165 d_messageCallback(std::move(messageCallback)), 0166 d_catchCodeAnalysisOutput(catchCodeAnalysisOutput), 0167 d_handleCppCommentsCallback(std::move(handleCppCommentsCallback)) 0168 { 0169 } 0170 0171 // MANIPULATORS 0172 std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance& compiler, 0173 clang::StringRef file) override 0174 { 0175 // try our best not to bail on compilation errors 0176 clang::FrontendOptions& fOpts = compiler.getFrontendOpts(); 0177 fOpts.FixWhatYouCan = true; 0178 fOpts.FixAndRecompile = true; 0179 fOpts.FixToTemporaries = true; 0180 0181 // Attempt to obliterate any -Werror options 0182 clang::DiagnosticOptions& dOpts = compiler.getDiagnosticOpts(); 0183 dOpts.Warnings = {"-Wno-everything"}; 0184 0185 return std::make_unique<LogicalDepConsumer>(&compiler.getASTContext(), 0186 file, 0187 d_memDb, 0188 d_prefix, 0189 d_nonLakosianDirs, 0190 d_thirdPartyDirs, 0191 d_visitLog_p, 0192 d_staticFnHandler_p, 0193 d_messageCallback, 0194 d_catchCodeAnalysisOutput, 0195 d_handleCppCommentsCallback); 0196 } 0197 0198 bool BeginSourceFileAction(clang::CompilerInstance& ci) override 0199 { 0200 d_filenameCallback(getCurrentFile().str()); 0201 0202 return SyntaxOnlyAction::BeginSourceFileAction(ci); 0203 } 0204 0205 void EndSourceFileAction() override 0206 // Callback at the end of processing a single input 0207 { 0208 d_staticFnHandler_p->writeOutToDb(); 0209 d_staticFnHandler_p->reset(); 0210 } 0211 }; 0212 0213 } // namespace 0214 0215 namespace Codethink::lvtclp { 0216 0217 LogicalDepActionFactory::LogicalDepActionFactory( 0218 lvtmdb::ObjectStore& memDb, 0219 std::filesystem::path prefix, 0220 std::vector<std::filesystem::path> nonLakosians, 0221 std::vector<std::pair<std::string, std::string>> thirdPartyDirs, 0222 std::function<void(const std::string&)> filenameCallback, 0223 std::optional<std::function<void(const std::string&, long)>> messageCallback, 0224 bool catchCodeAnalysisOutput, 0225 std::optional<HandleCppCommentsCallback_f> handleCppCommentsCallback): 0226 d_memDb(memDb), 0227 d_prefix(std::move(prefix)), 0228 d_nonLakosianDirs(std::move(nonLakosians)), 0229 d_thirdPartyDirs(std::move(thirdPartyDirs)), 0230 d_filenameCallback(std::move(filenameCallback)), 0231 d_messageCallback(std::move(messageCallback)), 0232 d_catchCodeAnalysisOutput(catchCodeAnalysisOutput), 0233 d_handleCppCommentsCallback(std::move(handleCppCommentsCallback)) 0234 { 0235 } 0236 0237 std::unique_ptr<clang::FrontendAction> LogicalDepActionFactory::create() 0238 { 0239 return std::make_unique<LogicalDepFrontendAction>(d_memDb, 0240 d_prefix, 0241 d_nonLakosianDirs, 0242 d_thirdPartyDirs, 0243 d_filenameCallback, 0244 d_messageCallback, 0245 d_catchCodeAnalysisOutput, 0246 d_handleCppCommentsCallback); 0247 } 0248 0249 } // namespace Codethink::lvtclp