【问题标题】:Why isn't libclang returning meaningful completion results?为什么 libclang 不返回有意义的完成结果?
【发布时间】:2013-03-30 08:09:48
【问题描述】:

我正在尝试了解如何使用 libclang 完成代码。我看过“Thinking beyond the compiler”,也看过 c-index-test,找到了一个简单的示例程序 here

我编译了该程序并在这个示例文件上运行它,我将它制作成类似于视频中的那个:

struct List {
    int Data;
    struct List *Next;
};

int sumListNode(struct List *Node) {
    int result = 0;
    for (; Node; Node = Node->Next)
        result = result + Node->
}

void test() {
    sumLi
}

如果我将程序指向 Node-> 之后的第一个不完整空间,它会吐出几个 C 关键字,但不会像视频所说的那样吐出 Next 或 Data。

如果我将它指向 sumLi 之后的空格,它会打印出相同的 C 关键字。如果我将 sumListNode 指向 sumLi 中具有“s”的列,我可以让它打印出 sumListNode,但即便如此,它也会将其分配为与其他关键字相同的优先级值,所以它实际上只是打印出我的所有内容可以放在那里而不是阅读光标下的内容并尝试做出明智的猜测。我只是抓住了最后一根稻草,希望将光标放在片段的开头而不是结尾会有所帮助。

我已经了解了很多关于 libclang 可以提供给我的数据类型以及如何从 doxygen 以及在 c-index-test 中进行操作的知识,但我只是还没有学会如何制作它给我相关的数据,以便我可以处理。

【问题讨论】:

    标签: llvm clang llvm-clang libclang


    【解决方案1】:

    首先,您应该尝试打印翻译单元的任何 CXDiagnostic 输出,因为任何错误都可能导致 clang 在您的代码中丢失(在您提到的非常简单的情况下,这不太可能发生)。

    其次,请注意 libclang 定义行号和列号的方式可能与您习惯的方式不同(即,如果您从文本编辑器获取行/列信息,您可能必须在列号上加 1与 clang 的定义保持同步)。

    第三,您可以使用 clang 编译器本身来测试编译选项和行/列信息的有效性。通过这种方式,您可以消除基于 libclang 的代码产生的不确定性。你可以例如使用以下命令行:

    clang++ -cc1 -fsyntax-only -code-completion-at FILENAME:LINE:COL CLANG_ARGS
    

    还请注意,clang_codeCompleteAt 仅在令牌的开头被调用并生成所有可能令牌的列表,客户端负责过滤结果,其中可能已在文本编辑器中输入了部分令牌.

    来自文档(重点是我的):

    在翻译单元的给定位置执行代码补全。

    此函数在源代码中的特定文件、行和列执行代码补全,提供基于补全上下文建议潜在代码 sn-ps 的结果。代码完成的基本模型是 Clang 将解析一个完整的源文件,执行语法检查,直到请求代码完成的位置。此时,一个特殊的代码完成标记被传递给解析器,解析器识别这个标记并根据 C/Objective-C/C++ 语法中的当前位置和语义分析的状态确定要提供什么完成。这些完成通过新的 CXCodeCompleteResults 结构返回。

    代码完成本身意味着当用户键入标点字符或空格时由客户端触发,此时代码完成位置将与光标重合。例如,如果 p 是一个指针,代码补全可能会在“-”之后触发,然后在 p-> 中的“>”之后触发。当代码完成位置在“>”之后时,完成结果将提供例如“p”指向的结构的成员。 客户端负责将光标放在当前输入的token的开头,然后根据token的内容过滤结果。例如,当对表达式 p->get 进行代码完成时,客户端应该在“>”之后提供该代码完成挂钩的位置(例如,指向“g”)。然后,客户端可以根据当前的令牌文本(“get”)过滤结果,只显示那些以“get”开头的结果。 此接口的目的是将代码完成结果的相对高延迟获取与基于每个字符的结果过滤分开,后者必须具有较低的延迟。

    以修改后的第二个示例为例:

    int main (int argc, char **argv) {
      int i = sumLi
      //      ^
    }
    

    应在标记的位置(即标记的开头)调用代码完成。然后,Clang 可以给出一长串结果,例如:

    • argc
    • sumListNode(<# struct List *Node #>)

    然后由您根据部分输入的sumLi 令牌过滤此列表并保留唯一相关的完成:sumListNode

    如果你了解 elisp,clang 的源代码包含一个用于 Emacs 的自动完成库,这是这种两级实现的一个很好的例子:

    trunk/utils/clang-completion-mode.el

    【讨论】:

    • 谢谢!这几乎解决了我的问题。我的文本编辑器说 Node->(here) 是第 33 列。但是,运行 clang 本身会在第 27 列放置关于没有任何内容的错误。看起来它将标签计为一列。对于第二个示例,它仍然会打印出很多关键字,而不仅仅是预期的“sumListNodes”。如果它们之间没有空格,Clang 的建议将无法编译。为了确定,我在整个专栏中尝试了那个。我想应该由我来理清实际的可能性吧?
    • 糟糕,我应该补充一点,我编辑了 test.c,以便在该点预期一个整数值,并且在作用域中声明了一个结构列表。只是为了确保铿锵能够理解真实的世界背景。尽管如此,它仍然没有达到我的预期。例如, int i = sumLilong 不会编译,但它给出了 'long' 作为与 sumListNodes 同等优先级的建议。
    • 是的,我在发送后意识到我的代码中的自动完成程序不会完成任何与输入内容不匹配的内容,所以这不是问题。很抱歉在您输入所有内容之前没有回来并这么说,但再次感谢您抽出时间提供帮助。我真的很感激。
    猜你喜欢
    • 1970-01-01
    • 2017-06-07
    • 1970-01-01
    • 2019-01-14
    • 1970-01-01
    • 2016-09-02
    • 1970-01-01
    • 1970-01-01
    • 2012-08-19
    相关资源
    最近更新 更多