如何使用Clang CompilerInstance完成?

时间:2016-05-16 18:15:13

标签: c++ clang llvm code-completion

我有一个库,它使用并公开了一个clang :: CompilerInstance。 如何使用CompilerInstance获取代码完成建议?

基本上我正在寻找一个具有以下签名的函数:

vector<string> completeSnippet(
  clang::CompilerInstance CI, 
  string codeSnippet,
  int completeAtIndex
);

有什么想法吗?

提前致谢

1 个答案:

答案 0 :(得分:4)

老实说,我没有弄清楚如何实施

vector<string> completeSnippet(
  clang::CompilerInstance CI, 
  string codeSnippet,
  int completeAtIndex
);

相反,我能提供的是

vector<std::string> completeSnippet(clang::CompilerInstance& ci,
                                    const std::string& filename,
                                    unsigned Line /* start from 1 */,
                                    unsigned Column /* start from 1 */);

如果您不太关心性能,可以使用解决方法,可以将codeSnippet存储到文件中,然后传递文件名。

由于我不知道ci的状态,例如,它是否有目标,我只是澄清主方法中的方法,您可以轻松地将其重构为函数。

int main()
{
    std::string Filename("test.cpp");
    unsigned Line = 7;
    unsigned Column = 5;
    clang::CompilerInstance ci;

    // 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));

    // Execute
    clang::SyntaxOnlyAction Act;
    if (Act.BeginSourceFile(ci, ci.getFrontendOpts().Inputs[0])) {
        Act.Execute();
        Act.EndSourceFile();
    }
}

我从PrintingCodeCompleteConsumerSema/CodeCompleteConsumer.cpp中的Sema/CodeCompleteConsumer.h复制了回调类的实现

class CustomCodeCompleteConsumer : public clang::CodeCompleteConsumer {
    clang::CodeCompletionTUInfo CCTUInfo;
public:
    CustomCodeCompleteConsumer(const clang::CodeCompleteOptions &CodeCompleteOpts)
    : clang::CodeCompleteConsumer(CodeCompleteOpts, false), CCTUInfo(new clang::GlobalCodeCompletionAllocator) {}

    void ProcessCodeCompleteResults(clang::Sema &SemaRef, clang::CodeCompletionContext Context,
                                    clang::CodeCompletionResult *Results,
                                    unsigned NumResults) override {
        std::stable_sort(Results, Results + NumResults, [](auto& lhs, auto& rhs) {
            return lhs.Priority > rhs.Priority;
        });
        using namespace clang;
        for (unsigned I = 0; I != NumResults; ++I) {
            std::string ccStr = "";
            llvm::raw_string_ostream OS(ccStr);
            OS << "COMPLETION: " << Results[I].Priority;
            switch (Results[I].Kind) {
                case CodeCompletionResult::RK_Declaration:
                    OS << "Decl : ";
                    OS << *Results[I].Declaration;
                    if (Results[I].Hidden)
                        OS << " (Hidden)";
                    if (CodeCompletionString *CCS
                        = Results[I].CreateCodeCompletionString(SemaRef, Context,
                                                                getAllocator(),
                                                                CCTUInfo,
                                                                includeBriefComments())) {
                            OS << " : " << CCS->getAsString();
                            if (const char *BriefComment = CCS->getBriefComment())
                                OS << " : " << BriefComment;
                        }

                    OS << '\n';
                    break;

                case CodeCompletionResult::RK_Keyword:
                    OS << "Keyword : ";
                    OS << Results[I].Keyword << '\n';
                    break;

                case CodeCompletionResult::RK_Macro: {
                    OS << "Macro : ";
                    OS << Results[I].Macro->getName();
                    if (CodeCompletionString *CCS
                        = Results[I].CreateCodeCompletionString(SemaRef, Context,
                                                                getAllocator(),
                                                                CCTUInfo,
                                                                includeBriefComments())) {
                            OS << " : " << CCS->getAsString();
                        }
                    OS << '\n';
                    break;
                }

                case CodeCompletionResult::RK_Pattern: {
                    OS << "Pattern : " 
                    << Results[I].Pattern->getAsString() << '\n';
                    break;
                }
            }
            OS.flush();
            std::cout << ccStr;
        }

    }

    void ProcessOverloadCandidates(clang::Sema &S, unsigned CurrentArg,
                                   clang::OverloadCandidate *Candidates,
                                   unsigned NumCandidates) {

    }

    clang::CodeCompletionAllocator &getAllocator() override {
        return CCTUInfo.getAllocator();
    }

    clang::CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
};

我对原始ProcessCodeCompleteResults做了一点改动,将信息输出到控制台。

我的头文件:

#define __STDC_CONSTANT_MACROS
#define __STDC_LIMIT_MACROS
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/FrontendActions.h>
#include <clang/Lex/Preprocessor.h>
#include <clang/Basic/TargetOptions.h>
#include <clang/Basic/TargetInfo.h>
#include <clang/Basic/LangOptions.h>
#include <clang/Basic/SourceManager.h>
#include <clang/Basic/SourceLocation.h>
#include <clang/Basic/FileManager.h>
#include <clang/Sema/Sema.h>
#include <clang/Sema/CodeCompleteOptions.h>
#include <clang/Sema/CodeCompleteConsumer.h>
#include <clang/Parse/ParseAST.h>
#include <clang/AST/ASTContext.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/Decl.h>
#include <llvm/Support/raw_ostream.h>
#include <iostream>

剩下的问题:

  • 我没有找到传递字符串而不是文件名
  • 的接口
  • 您可能需要额外的努力来处理返回的完成。

假设我们有两个测试文件:

<强> test1.cpp

void myFunc(int param) {

}

int main() {
    int count = 5;
    cou
    return 0;
}

<强>测试2.cpp

void myFunc(int param) {

}

int main() {
    int count = 5;
    myFunc
    return 0;
}

lang++ -cc1 -fsyntax-only -code-completion-at test2.cpp:7:4 test2.cppclang++ -cc1 -fsyntax-only -code-completion-at test1.cpp:7:4 test1.cpp输出相同的内容:

COMPLETION: __FUNCTION__
COMPLETION: __PRETTY_FUNCTION__
COMPLETION: _Nonnull
COMPLETION: _Null_unspecified
COMPLETION: _Nullable
COMPLETION: bool
COMPLETION: char
COMPLETION: class
COMPLETION: const
COMPLETION: Pattern : const_cast<<#type#>>(<#expression#>)
COMPLETION: count : [#int#]count
COMPLETION: Pattern : [#void#]delete <#expression#>
COMPLETION: Pattern : [#void#]delete [] <#expression#>
COMPLETION: double
COMPLETION: Pattern : dynamic_cast<<#type#>>(<#expression#>)
COMPLETION: enum
COMPLETION: extern
COMPLETION: Pattern : [#bool#]false
COMPLETION: float
COMPLETION: Pattern : goto <#label#>
COMPLETION: int
COMPLETION: long
COMPLETION: main : [#int#]main()
COMPLETION: myFunc : [#void#]myFunc(<#int param#>)
COMPLETION: Pattern : new <#type#>(<#expressions#>)
COMPLETION: Pattern : new <#type#>[<#size#>](<#expressions#>)
COMPLETION: operator
COMPLETION: Pattern : reinterpret_cast<<#type#>>(<#expression#>)
COMPLETION: Pattern : return <#expression#>
COMPLETION: short
COMPLETION: signed
COMPLETION: Pattern : [#size_t#]sizeof(<#expression-or-type#>)
COMPLETION: static
COMPLETION: Pattern : static_cast<<#type#>>(<#expression#>)
COMPLETION: struct
COMPLETION: Pattern : [#bool#]true
COMPLETION: Pattern : typedef <#type#> <#name#>
COMPLETION: Pattern : [#std::type_info#]typeid(<#expression-or-type#>)
COMPLETION: Pattern : typename <#qualifier#>::<#name#>
COMPLETION: Pattern : typeof <#expression#>
COMPLETION: Pattern : typeof(<#type#>)
COMPLETION: union
COMPLETION: unsigned
COMPLETION: Pattern : using namespace <#identifier#>
COMPLETION: void
COMPLETION: volatile
COMPLETION: wchar_t

与我的实施相同:

COMPLETION: 65 Keyword : __PRETTY_FUNCTION__
COMPLETION: 65 Keyword : __FUNCTION__
COMPLETION: 65 Keyword : __func__
COMPLETION: 50 Decl : myFunc : [#void#]myFunc(<#int param#>)
COMPLETION: 50 Decl : main : [#int#]main()
COMPLETION: 50 Keyword : short
COMPLETION: 50 Keyword : long
COMPLETION: 50 Keyword : signed
COMPLETION: 50 Keyword : unsigned
COMPLETION: 50 Keyword : void
COMPLETION: 50 Keyword : char
COMPLETION: 50 Keyword : int
COMPLETION: 50 Keyword : float
COMPLETION: 50 Keyword : double
COMPLETION: 50 Keyword : enum
COMPLETION: 50 Keyword : struct
COMPLETION: 50 Keyword : union
COMPLETION: 50 Keyword : const
COMPLETION: 50 Keyword : volatile
COMPLETION: 50 Keyword : bool
COMPLETION: 50 Keyword : class
COMPLETION: 50 Keyword : wchar_t
COMPLETION: 50 Keyword : auto
COMPLETION: 50 Keyword : char16_t
COMPLETION: 50 Keyword : char32_t
COMPLETION: 50 Keyword : _Nonnull
COMPLETION: 50 Keyword : _Null_unspecified
COMPLETION: 50 Keyword : _Nullable
COMPLETION: 40 Pattern : typedef <#type#> <#name#>
COMPLETION: 40 Pattern : if(<#condition#>){<#statements#>
}
COMPLETION: 40 Pattern : switch(<#condition#>){
}
COMPLETION: 40 Pattern : while(<#condition#>){<#statements#>
}
COMPLETION: 40 Pattern : do{<#statements#>
}while(<#expression#>)
COMPLETION: 40 Pattern : for(<#init-statement#>;<#condition#>;<#inc-expression#>){
<#statements#>
}
COMPLETION: 40 Pattern : return <#expression#>
COMPLETION: 40 Pattern : goto <#label#>
COMPLETION: 40 Pattern : using namespace <#identifier#>
COMPLETION: 40 Keyword : extern
COMPLETION: 40 Keyword : static
COMPLETION: 40 Pattern : [#bool#]true
COMPLETION: 40 Pattern : [#bool#]false
COMPLETION: 40 Pattern : dynamic_cast<<#type#>>(<#expression#>)
COMPLETION: 40 Pattern : static_cast<<#type#>>(<#expression#>)
COMPLETION: 40 Pattern : reinterpret_cast<<#type#>>(<#expression#>)
COMPLETION: 40 Pattern : const_cast<<#type#>>(<#expression#>)
COMPLETION: 40 Pattern : [#std::type_info#]typeid(<#expression-or-type#>)
COMPLETION: 40 Pattern : new <#type#>(<#expressions#>)
COMPLETION: 40 Pattern : new <#type#>[<#size#>](<#expressions#>)
COMPLETION: 40 Pattern : [#void#]delete <#expression#>
COMPLETION: 40 Pattern : [#void#]delete [] <#expression#>
COMPLETION: 40 Pattern : [#std::nullptr_t#]nullptr
COMPLETION: 40 Pattern : [#size_t#]alignof(<#type#>)
COMPLETION: 40 Pattern : [#bool#]noexcept(<#expression#>)
COMPLETION: 40 Pattern : [#size_t#]sizeof...(<#parameter-pack#>)
COMPLETION: 40 Pattern : [#size_t#]sizeof(<#expression-or-type#>)
COMPLETION: 40 Pattern : typename <#qualifier#>::<#name#>
COMPLETION: 40 Pattern : decltype(<#expression#>)
COMPLETION: 40 Pattern : typeof <#expression#>
COMPLETION: 40 Pattern : typeof(<#type#>)
COMPLETION: 40 Keyword : operator
COMPLETION: 34 Decl : count : [#int#]count

虽然我已按priority

订购了它们

您可以参考ASTUnit::CodeComplete中的AugmentedCodeCompleteConsumer::ProcessCodeCompleteResultslib/Frontend/ASTUnit.cpp,详细了解clang_codeCompleteAt的逻辑