我试图在clang中为codecompletion创建虚拟文件.不幸的是,我的应用程序是segfaults.
我有以下设置:
我有以下设置:
auto createVirtualFile = []( clang::CompilerInstance& ci,std::string name,llvm::StringRef input ) { std::unique_ptr<llvm::MemoryBuffer> MB(llvm::MemoryBuffer::getMemBuffer(input,name)); return std::move(MB); };
创建文件后,我设置了CodeCompletConsumer:
auto setupCodeComplete = []( clang::CompilerInstance& ci,std::string File,int Line,int Column ) { auto& F = ci.getFrontendOpts(); F.CodeCompletionAt.FileName = File; F.CodeCompletionAt.Line = Line; F.CodeCompletionAt.Column = Column; clang::FrontendInputFile FrontFile(File,clang::IK_CXX); //F.Inputs.push_back(FrontFile); ci.createCodeCompletionConsumer(); return FrontFile; };
auto runCodeCompleteAt = [] ( clang::CompilerInstance& ci,std::string Filename,std::string Code,int Column ) { auto fid = createVirtualFile(ci,Filename,Code); auto File = setupCodeComplete(ci,Line,Column); clang::SyntaxOnlyAction Act; if (Act.BeginSourceFile(ci,File )) { Act.Execute(); // segfault Act.EndSourceFile(); } }; auto runExample = [](auto& ci){ runCodeCompleterAt(ci,"test.cpp","std::cou",1,7); }
我很欣赏任何提示.
解决方法
问题是虽然你可以将llvm :: MemoryBuffer添加到clang :: FrontendInputFile中,但是clang :: SyntaxOnlyAction不接受这样的输入,它会导致断言失败.正如我在
previous answer中所说,您可能希望在lib / Frontend / ASTUnit.cpp中查看ASTUnit :: CodeComplete.
实际上,您可以使用remappedFiles将文件名链接到缓冲区:
int main() { unsigned Line = 2; unsigned Column = 13; clang::CompilerInstance ci; llvm::StringRef codeStr("void MyFoo() {}\nint main() {My return 0}"); // Just a dummy filename,the file even doesnt' exist. std::string Filename("virtualFile.cpp"); std::unique_ptr<llvm::MemoryBuffer> MB(llvm::MemoryBuffer::getMemBuffer(codeStr,Filename)); // Create diagnostics and target ci.createDiagnostics(); std::shared_ptr<clang::TargetOptions> to = std::make_shared<clang::TargetOptions>(); // clang -v //to->Triple = "x86_64-pc-win32"; //to->Triple = "x86_64-apple-darwin"; to->Triple = "x86_64-apple-darwin15"; ci.setTarget(clang::TargetInfo::CreateTargetInfo(ci.getDiagnostics(),to)); // Create language options clang::LangOptions &lo = ci.getLangOpts(); lo.CPlusPlus = true; lo.CPlusPlus11 = true; // Create code complete options clang::CodeCompleteOptions cco; cco.IncludeMacros = 0; cco.IncludeCodePatterns = 1; cco.IncludeGlobals = 1; cco.IncludeBriefComments = 1; // Set up the callback,I will go back to this callback class later auto pCustomCodeCompleteConsumer = new CustomCodeCompleteConsumer(cco); ci.setCodeCompletionConsumer(pCustomCodeCompleteConsumer); // Set up code complete postions & file // Until now I didn't find a way to pass in a string rather than a file name clang::FrontendOptions& frontendOpts = ci.getFrontendOpts(); frontendOpts.CodeCompletionAt.FileName = Filename; frontendOpts.CodeCompletionAt.Line = Line; frontendOpts.CodeCompletionAt.Column = Column; frontendOpts.Inputs.push_back(clang::FrontendInputFile(Filename,clang::InputKind::IK_CXX)); clang::PreprocessorOptions& preprocessorOpts = ci.getPreprocessorOpts(); preprocessorOpts.clearRemappedFiles(); preprocessorOpts.addRemappedFile(Filename,MB.release()); // Execute clang::SyntaxOnlyAction Act; if (Act.BeginSourceFile(ci,ci.getFrontendOpts().Inputs[0])) { Act.Execute(); Act.EndSourceFile(); } }
输出包含COMLELE:50 Decl:MyFoo:[#void#] MyFoo().
我从代码段得到了这个答案
PreprocessorOpts.clearRemappedFiles(); PreprocessorOpts.RetainRemappedFileBuffers = true; for (const auto &RemappedFile : RemappedFiles) { PreprocessorOpts.addRemappedFile(RemappedFile.first,RemappedFile.second); OwnedBuffers.push_back(RemappedFile.second); }
在ASTUnit :: CodeComplete中.
我相信您可能希望阅读AugmentedCodeCompleteConsumer以使用这些完成提示.