2013-04-08 29 views
9

Tôi đang cố gắng hiểu cách hoàn thành mã bằng libclang. Tôi đã xem "Suy nghĩ vượt ra ngoài trình biên dịch" và tôi đã xem qua thử nghiệm c-index và tôi đã tìm thấy một chương trình mẫu đơn giản hereTại sao libclang không trả lại kết quả có ý nghĩa?

Tôi biên dịch chương trình đó và chạy nó trên tệp mẫu này mà tôi đã giống với một trong đoạn video:

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 
} 

Nếu tôi chỉ chương trình tại các không gian không đầy đủ đầu tiên sau khi node->, nó spits ra một vài từ khóa C, nhưng nó không nhổ ra Next hoặc dữ liệu như video nói nó nên.

Nếu tôi trỏ nó vào không gian sau sumLi, nó sẽ in ra cùng các từ khóa C đó. Tôi có thể lấy nó để in ra sumListNode nếu tôi chỉ nó vào cột có 's' trong sumLi, nhưng thậm chí nó gán giá trị ưu tiên giống như các từ khóa khác, vì vậy nó thực sự chỉ in ra mọi thứ mà tôi có thể đặt ở đó thay vì đọc những gì dưới con trỏ và cố gắng đoán một cách thông minh. Tôi chỉ đang nắm lấy ống hút với hy vọng rằng việc đặt con trỏ vào đầu đoạn thay vì kết thúc sẽ giúp ích gì đó.

Tôi đã học được rất nhiều về loại libclang dữ liệu có thể cung cấp cho tôi và cách hoạt động với nó từ doxygen, và từ poking xung quanh trong c-index-test, nhưng tôi chưa học cách làm nó cung cấp cho tôi dữ liệu liên quan để tôi có một cái gì đó để làm việc.

Trả lời

9

Trước tiên, bạn nên thử in bất kỳ đầu ra CXDiagnostic do đơn vị dịch, vì bất kỳ lỗi nào cũng có thể làm cho mã bị mất trong mã của bạn (điều này rất khó xảy ra trong trường hợp rất đơn giản mà bạn đề cập). Thứ hai, hãy lưu ý rằng libclang xác định số dòng và cột theo cách có thể khác với những gì bạn đang sử dụng (tức là nếu bạn đang nhận thông tin line/col từ trình soạn thảo, bạn có thể phải thêm 1 vào col số được đồng bộ với định nghĩa của clang).

Thứ ba, bạn có thể sử dụng trình biên dịch clang để kiểm tra tính hợp lệ của các tùy chọn biên dịch và thông tin dòng/cột. Bằng cách này, bạn loại bỏ sự không chắc chắn xuất phát từ mã dựa trên libclang của bạn. Bạn có thể ví dụ: sử dụng dòng lệnh sau:

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

Cũng lưu ý rằng clang_codeCompleteAt có nghĩa là để được gọi là chỉ vào đầu của một mã thông báo và tạo ra một danh sách của tất cả các thẻ có thể, khách hàng là chịu trách nhiệm về lọc kết quả với mã thông báo một phần tiềm năng đã được nhập trong trình chỉnh sửa văn bản.

Từ các tài liệu (nhấn mạnh là của tôi):

Thực hiện hoàn thành mã tại một địa điểm được đưa ra trong một đơn vị dịch thuật.

Chức năng này thực hiện hoàn thành mã tại một tệp, dòng và cột cụ thể trong mã nguồn, cung cấp kết quả đề xuất các đoạn mã tiềm năng dựa trên ngữ cảnh hoàn thành. Mô hình cơ bản để hoàn thành mã là Clang sẽ phân tích cú pháp một tệp nguồn hoàn chỉnh, thực hiện kiểm tra cú pháp đến vị trí yêu cầu hoàn thành mã. Tại thời điểm đó, một mã thông báo hoàn thành mã đặc biệt được chuyển tới trình phân tích cú pháp, nhận dạng mã thông báo này và xác định, dựa trên vị trí hiện tại trong ngữ pháp C/Objective-C/C++ và trạng thái phân tích ngữ nghĩa, những gì hoàn thành để cung cấp. Những lần hoàn thành này được trả về thông qua cấu trúc CXCodeCompleteResults mới.

Tự hoàn thành mã có nghĩa là được kích hoạt bởi ứng dụng khách khi người dùng nhập ký tự dấu câu hoặc khoảng trắng, tại thời điểm vị trí hoàn thành mã sẽ trùng với con trỏ. Ví dụ, nếu p là một con trỏ, hoàn thành mã có thể được kích hoạt sau "-" và sau đó sau ">" trong p->. Khi vị trí hoàn thành mã là afer ">", kết quả hoàn thành sẽ cung cấp, ví dụ: các thành viên của cấu trúc "p" trỏ tới. Khách hàng chịu trách nhiệm đặt con trỏ ở đầu mã thông báo hiện đang được nhập, sau đó lọc kết quả dựa trên nội dung của mã thông báo. Ví dụ: khi hoàn thành mã cho biểu thức p-> get, ứng dụng khách sẽ cung cấp vị trí ngay sau ">" (ví dụ: trỏ vào "g") đến móc hoàn thành mã này. Sau đó, khách hàng có thể lọc kết quả dựa trên văn bản mã thông báo hiện tại ("get"), chỉ hiển thị các kết quả bắt đầu bằng "get". Mục đích của giao diện này là tách biệt việc thu thập kết quả hoàn thành độ trễ tương đối cao từ việc lọc kết quả theo cơ sở cho mỗi ký tự, độ trễ phải thấp hơn.

Lấy ví dụ thứ hai sửa đổi của bạn:

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

hoàn Mã nên được gọi là ở vị trí đánh dấu (ví dụ: ở phần đầu của token). Clang sau đó có thể đưa ra một danh sách dài các kết quả bao gồm ví dụ:

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

Đó là sau đó tùy thuộc vào bạn để lọc danh sách này dựa trên vào phần sumLi token và giữ chỉ hoàn thành có liên quan: sumListNode.

Nếu bạn hiểu elisp, nguồn kêu vang của chứa một thư viện tự động hoàn thành cho Emacs, mà là một ví dụ tốt về thực hiện hai cấp này:

trunk/utils/clang-completion-mode.el

+0

Cảm ơn bạn! Điều đó khá cố định vấn đề của tôi. Trình soạn thảo văn bản của tôi nói rằng Node -> (ở đây) là cột 33. Tuy nhiên, hãy chạy các lỗi, không đặt bất kỳ thứ gì ở cột 27. Có vẻ như nó đếm các tab như một cột đơn. Đối với ví dụ thứ hai, nó vẫn in ra rất nhiều từ khóa thay vì chỉ là 'sumListNodes' dự kiến. Không có một khoảng trống giữa chúng, những lời đề nghị của Clang sẽ không biên dịch. Tôi đã thử một cái trên toàn bộ cột để chắc chắn. Tôi đoán đó là để tôi phân loại các khả năng thực tế? – John

+0

Rất tiếc, tôi nên thêm rằng tôi đã chỉnh sửa test.c sao cho nó được mong đợi là giá trị số nguyên tại điểm đó và danh sách struct được khai báo trong phạm vi. Chỉ để đảm bảo có một ngữ cảnh thế giới thực cho tiếng kêu vang. Nó vẫn không đưa ra những gì tôi mong đợi. Ví dụ, int i = sumLilong sẽ không biên dịch, nhưng nó đã cho 'long' như một gợi ý có mức độ ưu tiên bằng nhau như sumListNodes. – John

+0

Tôi đã chỉnh sửa câu trả lời của mình để thử trả lời những câu hỏi đó. – Francesco

Các vấn đề liên quan