Code Monkey home page Code Monkey logo

clang-rs's Introduction

clang-rs

Crate Documentation CI

A somewhat idiomatic Rust wrapper for libclang.

Supported on the stable, beta, and nightly Rust channels.
Minimum supported Rust version: 1.40.0

Released under the Apache License 2.0.

Supported Versions

To target a version of libclang, enable one of the following Cargo features:

  • clang_3_5 - requires libclang 3.5 or later
  • clang_3_6 - requires libclang 3.6 or later
  • clang_3_7 - requires libclang 3.7 or later
  • clang_3_8 - requires libclang 3.8 or later
  • clang_3_9 - requires libclang 3.9 or later
  • clang_4_0 - requires libclang 4.0 or later
  • clang_5_0 - requires libclang 5.0 or later
  • clang_6_0 - requires libclang 6.0 or later
  • clang_7_0 - requires libclang 7.0 or later
  • clang_8_0 - requires libclang 8.0 or later
  • clang_9_0 - requires libclang 9.0 or later
  • clang_10_0 - requires libclang 10.0 or later

If you do not enable one of these features, the API provided by libclang 3.5 will be available by default.

Dependencies

See here for information on this crate's dependencies.

clang-rs's People

Contributors

carlosmn avatar dansnow avatar gitter-badger avatar jarcho avatar kitcatier avatar kylemayes avatar madsmtm avatar mexus avatar mo-xiaoming avatar mrkline avatar sertel avatar t0suj4 avatar tmandry avatar vincentisambart avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

clang-rs's Issues

`Clang` can be constructed without `Clang::new()`

It's possible to construct Clang with

let cl = clang::Clang;

instead of

let cl = clang::Clang::new().unwrap();

This violates the requirement that only one Clang object exists per thread. The way to fix it is to give the struct a private inner type.

struct ClangInner; // Private, so can't construct `Clang` without `Clang::new()`

pub struct Clang(ClangInner);

Update to clang-sys 0.8

Hey,

any particular reason you haven't bumped the clang-sys dependency? 0.8 enables me to build under OS X.

completion_test fails with clang15.0.3

Using main branch with clang15.0.3, run cargo test locally, I got error

libclang: clang version 15.0.3 (https://github.com/llvm/llvm-project.git 4a2c05b05ed07f1f620e94f6524a8b4b2760a0b1)
thread 'test' panicked at 'assertion failed: `(left == right)`
  left: `7`,
 right: `6`', tests/completion.rs:58:13
stack backtrace:
   0: rust_begin_unwind
             at /rustc/a6b7274a462829f8ef08a1ddcdcec7ac80dbf3e1/library/std/src/panicking.rs:556:5
   1: core::panicking::panic_fmt
             at /rustc/a6b7274a462829f8ef08a1ddcdcec7ac80dbf3e1/library/core/src/panicking.rs:142:14
   2: core::panicking::assert_failed_inner
   3: core::panicking::assert_failed
             at /rustc/a6b7274a462829f8ef08a1ddcdcec7ac80dbf3e1/library/core/src/panicking.rs:181:5
   4: tests::completion_test::test::{{closure}}
             at ./tests/completion.rs:58:13
   5: tests::with_temporary_file::{{closure}}
             at ./tests/tests.rs:69:55
   6: tests::with_temporary_files::{{closure}}
             at ./tests/tests.rs:80:9
   7: tests::with_temporary_directory
             at ./tests/tests.rs:64:5
   8: tests::with_temporary_files
             at ./tests/tests.rs:73:5
   9: tests::with_temporary_file
             at ./tests/tests.rs:69:5
  10: tests::completion_test::test
             at ./tests/completion.rs:17:5
  11: tests::test
             at ./tests/tests.rs:123:5
  12: tests::test::{{closure}}
             at ./tests/tests.rs:118:1
  13: core::ops::function::FnOnce::call_once
             at /rustc/a6b7274a462829f8ef08a1ddcdcec7ac80dbf3e1/library/core/src/ops/function.rs:251:5
  14: core::ops::function::FnOnce::call_once
             at /rustc/a6b7274a462829f8ef08a1ddcdcec7ac80dbf3e1/library/core/src/ops/function.rs:251:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
test test ... FAILED

It seems this clang version produces different results.get_results()

[
    CompletionResult {
        kind: FieldDecl,
        string: CompletionString {
            chunks: [
                ResultType(
                    "int",
                ),
                TypedText(
                    "a",
                ),
            ],
        },
    },
    CompletionResult {
        kind: StructDecl,
        string: CompletionString {
            chunks: [
                TypedText(
                    "A",
                ),
                Text(
                    "::",
                ),
            ],
        },
    },
    CompletionResult {
        kind: FieldDecl,
        string: CompletionString {
            chunks: [
                ResultType(
                    "int",
                ),
                TypedText(
                    "b",
                ),
            ],
        },
    },
    CompletionResult {
        kind: FieldDecl,
        string: CompletionString {
            chunks: [
                ResultType(
                    "int",
                ),
                TypedText(
                    "c",
                ),
            ],
        },
    },
    CompletionResult {
        kind: Destructor,
        string: CompletionString {
            chunks: [
                ResultType(
                    "void",
                ),
                TypedText(
                    "~A",
                ),
                LeftParenthesis,
                RightParenthesis,
            ],
        },
    },
    CompletionResult {
        kind: Method,
        string: CompletionString {
            chunks: [
                ResultType(
                    "A &",
                ),
                TypedText(
                    "operator=",
                ),
                LeftParenthesis,
                Placeholder(
                    "const A &",
                ),
                RightParenthesis,
            ],
        },
    },
    CompletionResult {
        kind: Method,
        string: CompletionString {
            chunks: [
                ResultType(
                    "A &",
                ),
                TypedText(
                    "operator=",
                ),
                LeftParenthesis,
                Placeholder(
                    "A &&",
                ),
                RightParenthesis,
            ],
        },
    },
]

Entity as enum

Did you consider making Entity an enum? It would nable the use of pattern matching.

clang-rs does not search LIBRARY_PATH and instead picks libraries in /usr/lib/xxx

It seems that clang-rs does not search for libraries in the environment variable LIBRARY_PATH during execution of the build.rs script.

I am using GUIX (like NIX) and my library path is /gnu/store/qb41j953iam58gj3cwsz9jlnnfn25cwa-profile/lib.
In that folder there is a libclang and libLLVM etc.
But it seems that the build.rs script is instead linking with the libclang and libllvm that is present in /lib/x86_64-linux-gnu/.
This leads to all sorts of linker errors, see snippet below:

  = note: ld: /lib/x86_64-linux-gnu/libedit.so.2: undefined reference to `__isoc23_wcstol@GLIBC_2.38'
          ld: /lib/x86_64-linux-gnu/libLLVM-17.so.1: undefined reference to `arc4random@GLIBC_2.36'
          ld: /lib/x86_64-linux-gnu/libbsd.so.0: undefined reference to `__isoc23_strtoimax@GLIBC_2.38'
          ld: /lib/x86_64-linux-gnu/libLLVM-17.so.1: undefined reference to `__isoc23_strtoull@GLIBC_2.38'
          ld: /lib/x86_64-linux-gnu/libLLVM-17.so.1: undefined reference to `__isoc23_sscanf@GLIBC_2.38'
          ld: /usr/lib/llvm-17/lib/libclang-17.0.6.so: undefined reference to `__isoc23_strtoul@GLIBC_2.38'
          ld: /lib/x86_64-linux-gnu/libLLVM-17.so.1: undefined reference to `std::condition_variable::wait(std::unique_lock<std::mutex>&)@GLIBCXX_3.4.30'
          ld: /lib/x86_64-linux-gnu/libLLVM-17.so.1: undefined reference to `fmodf@GLIBC_2.38'
          ld: /usr/lib/llvm-17/lib/libclang-17.0.6.so: undefined reference to `__isoc23_strtol@GLIBC_2.38'
          ld: /lib/x86_64-linux-gnu/libLLVM-17.so.1: undefined reference to `fmod@GLIBC_2.38'
          ld: /lib/x86_64-linux-gnu/libLLVM-17.so.1: undefined reference to `__isoc23_scanf@GLIBC_2.38'
          ld: /lib/x86_64-linux-gnu/libbsd.so.0: undefined reference to `__isoc23_strtoumax@GLIBC_2.38'
          ld: /lib/x86_64-linux-gnu/libLLVM-17.so.1: undefined reference to `__isoc23_strtoll@GLIBC_2.38'

Why fix this?

The LIBRARY_PATH variable is a convention established by gcc, and it makes sense to follow it.
See here https://gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html#index-LIBRARY_005fPATH

How to fix this:

If LIBRARY_PATH is set, the build.rs script should search for libclang and similar in all the paths specified there, before it looks anywhere else. This is compatible with how gcc works.

Update EntityKind

The CXCursor_TranslationUnit change value in LLVM 15 from 300 to 350 (see this commit).
The clang::EntityKind::TranslationUnit value is then wrong and a translation unit entity kind become NotImplemented.

libclang is not loaded while having bindgen as dependency

This works

Cargo.toml:-

[package]
name = "bindgen_with_clang"
version = "0.1.0"
edition = "2018"

[build-dependencies]
#bindgen = "0.57.0" #uncommenting this panics the build.rs
clang = "1.0.3"

build.rs:-

use clang::*;

fn main() {
    let clang = Clang::new().unwrap();
    let index = Index::new(&clang, false, false);
    let tu = index.parser("test.hpp").parse().unwrap();
}

But un-commentating bindgen in Cargo.toml does not work. It gives me following error:-

   Compiling bindgen_with_clang v0.1.0 (/home/smit/bindgen_with_clang)
error: failed to run custom build command for `bindgen_with_clang v0.1.0 (/home/smit/bindgen_with_clang)`

Caused by:
  process didn't exit successfully: `/home/smit/bindgen_with_clang/target/debug/build/bindgen_with_clang-b4cabdc5f6bc0d97/build-script-build` (exit code: 101)
  --- stderr
  thread 'main' panicked at 'a `libclang` shared library is not loaded on this thread', /home/smit/.cargo/registry/src/github.com-1ecc6299db9ec823/clang-sys-1.1.1/src/lib.rs:1680:1
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Add a switch for cpp?

clang.exe has a switch to parse .h as cpp header file with "-x c++", or use clang++.exe

I want to parse a c++ header file with .h extension, now I can only rename it to .hpp to get parse correct.

Does libclang support this? Can this add to clang-rs?

Location information for Types

Hi,

Is there any possibility to access the location information for a type?
I'm doing roughly the following:

fn_entity
  .get_type().unwrap()
  .get_argument_types().unwrap()
  .into_iter()
  .for_each(|t:Type| {
    // get location information for 'type' here
  })

Thanks a lot,
Sebastian.

`struct Clang` should not implement `Send`

Creating an instance of Clang involves calling clang-sys::load() which dynamically loads the clang library for the currently executing thread.

With Clang: Send (which is implemented automatically due to the auto-trait rules) the abstraction leaks when you do something like:

let clang = Clang::new();
std::thread::spawn(|| {
    /* use clang here */
});

When code is written this way, clang attempts to directly access functions from libclang without checking whether the library is loaded and fail at the assert here.

This bug occurred in actual code here https://github.com/twistedfall/opencv-rust/blob/master/build.rs#L99-L116

Ultimately I think using thread-local storage here is really an instance of superfluous complexity and the library would be way better off with plain global shared variable with an atomic and a std::sync::Once or a lazy_static.

The function `is_function_like_macro` is wrongly mapped

Currently maps to:

pub fn is_function_like_macro(&self) -> bool {
        unsafe { clang_Cursor_isFunctionInlined(self.raw) != 0 }
    }

Should be:

pub fn is_function_like_macro(&self) -> bool {
        unsafe { clang_Cursor_isMacroFunctionLike(self.raw) != 0 }
    }

I will create a pull request for this change in a second.

Crazy token results; either partial or completely missing

Hey Kyle!

I was just trying out clang-rs and the results I'm seeing from a trivial tokenization are pretty wonky. I'll share with you the simplest cases I've managed to pinpoint and hopefully you can shed some light on what's going on.

NOTE: I've tested both of these with clang_7_0 and clang_10_0. Both show the same results.

Missing annotated tokens

The first issue I was seeing was with partial token results. Note that the last expression in the C source is f.a = 0;, but note that the last token in the annotated token list is just f with no children. The normal tokens look just fine and include identifiers for f and a in the assignment.

simple.c

typedef struct
{
  char *a;
} foo;

int main()
{
  foo f;
  f.a = 0;
}

main.rs

extern crate clang;

fn main() {
  let clang = clang::Clang::new().unwrap();
  let index = clang::Index::new(&clang, false, false);
  let translation_unit = index
    .parser("test/simple.c")
    .detailed_preprocessing_record(true)
    .parse()
    .expect("failed to parse");
  println!("tu: {:#?}", translation_unit);

  let diags = translation_unit.get_diagnostics();
  println!("diags: {:?}", diags);

  let tokens = translation_unit
    .get_entity()
    .get_range()
    .unwrap()
    .tokenize();
  println!("tokens: {:#?}", tokens);

  let annotated_tokens = translation_unit.annotate(&tokens);
  println!("annotated: {:#?}", annotated_tokens);

  println!(
    "children: {:#?}",
    annotated_tokens
      .iter()
      .map(|&t| t.map(|t| t.get_children()))
  );
}

stdout

tu: TranslationUnit {
    spelling: "test/simple.c",
}
diags: []
tokens: [
    Token {
        kind: Keyword,
        spelling: "typedef",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 1,
                column: 1,
                offset: 0,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 1,
                column: 8,
                offset: 7,
            },
        },
    },
    Token {
        kind: Keyword,
        spelling: "struct",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 1,
                column: 9,
                offset: 8,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 1,
                column: 15,
                offset: 14,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: "{",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 2,
                column: 1,
                offset: 15,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 2,
                column: 2,
                offset: 16,
            },
        },
    },
    Token {
        kind: Keyword,
        spelling: "char",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 3,
                column: 3,
                offset: 19,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 3,
                column: 7,
                offset: 23,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: "*",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 3,
                column: 8,
                offset: 24,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 3,
                column: 9,
                offset: 25,
            },
        },
    },
    Token {
        kind: Identifier,
        spelling: "a",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 3,
                column: 9,
                offset: 25,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 3,
                column: 10,
                offset: 26,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: ";",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 3,
                column: 10,
                offset: 26,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 3,
                column: 11,
                offset: 27,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: "}",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 4,
                column: 1,
                offset: 28,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 4,
                column: 2,
                offset: 29,
            },
        },
    },
    Token {
        kind: Identifier,
        spelling: "foo",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 4,
                column: 3,
                offset: 30,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 4,
                column: 6,
                offset: 33,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: ";",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 4,
                column: 6,
                offset: 33,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 4,
                column: 7,
                offset: 34,
            },
        },
    },
    Token {
        kind: Keyword,
        spelling: "int",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 1,
                offset: 36,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 4,
                offset: 39,
            },
        },
    },
    Token {
        kind: Identifier,
        spelling: "main",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 5,
                offset: 40,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 9,
                offset: 44,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: "(",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 9,
                offset: 44,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 10,
                offset: 45,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: ")",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 10,
                offset: 45,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 11,
                offset: 46,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: "{",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 7,
                column: 1,
                offset: 47,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 7,
                column: 2,
                offset: 48,
            },
        },
    },
    Token {
        kind: Identifier,
        spelling: "foo",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 8,
                column: 3,
                offset: 51,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 8,
                column: 6,
                offset: 54,
            },
        },
    },
    Token {
        kind: Identifier,
        spelling: "f",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 8,
                column: 7,
                offset: 55,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 8,
                column: 8,
                offset: 56,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: ";",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 8,
                column: 8,
                offset: 56,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 8,
                column: 9,
                offset: 57,
            },
        },
    },
    Token {
        kind: Identifier,
        spelling: "f",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 3,
                offset: 60,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 4,
                offset: 61,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: ".",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 4,
                offset: 61,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 5,
                offset: 62,
            },
        },
    },
    Token {
        kind: Identifier,
        spelling: "a",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 5,
                offset: 62,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 6,
                offset: 63,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: "=",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 7,
                offset: 64,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 8,
                offset: 65,
            },
        },
    },
    Token {
        kind: Literal,
        spelling: "0",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 9,
                offset: 66,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 10,
                offset: 67,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: ";",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 10,
                offset: 67,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 11,
                offset: 68,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: "}",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 10,
                column: 1,
                offset: 69,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 10,
                column: 2,
                offset: 70,
            },
        },
    },
]
annotated: [
    Some(
        Entity {
            kind: TypedefDecl,
            display_name: Some(
                "foo",
            ),
            location: Some(
                SourceLocation {
                    file: Some(
                        File {
                            path: "test/simple.c",
                        },
                    ),
                    line: 4,
                    column: 3,
                    offset: 30,
                },
            ),
        },
    ),
    Some(
        Entity {
            kind: TypedefDecl,
            display_name: Some(
                "foo",
            ),
            location: Some(
                SourceLocation {
                    file: Some(
                        File {
                            path: "test/simple.c",
                        },
                    ),
                    line: 4,
                    column: 3,
                    offset: 30,
                },
            ),
        },
    ),
    None,
    None,
    Some(
        Entity {
            kind: FieldDecl,
            display_name: Some(
                "a",
            ),
            location: Some(
                SourceLocation {
                    file: Some(
                        File {
                            path: "test/simple.c",
                        },
                    ),
                    line: 3,
                    column: 9,
                    offset: 25,
                },
            ),
        },
    ),
    None,
    None,
    None,
    Some(
        Entity {
            kind: StructDecl,
            display_name: None,
            location: Some(
                SourceLocation {
                    file: Some(
                        File {
                            path: "test/simple.c",
                        },
                    ),
                    line: 1,
                    column: 9,
                    offset: 8,
                },
            ),
        },
    ),
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    Some(
        Entity {
            kind: TypeRef,
            display_name: Some(
                "foo",
            ),
            location: Some(
                SourceLocation {
                    file: Some(
                        File {
                            path: "test/simple.c",
                        },
                    ),
                    line: 8,
                    column: 3,
                    offset: 51,
                },
            ),
        },
    ),
    None,
    None,
    Some(
        Entity {
            kind: CompoundStmt,
            display_name: None,
            location: Some(
                SourceLocation {
                    file: Some(
                        File {
                            path: "test/simple.c",
                        },
                    ),
                    line: 7,
                    column: 1,
                    offset: 47,
                },
            ),
        },
    ),
    Some(
        Entity {
            kind: DeclRefExpr,
            display_name: Some(
                "f",
            ),
            location: Some(
                SourceLocation {
                    file: Some(
                        File {
                            path: "test/simple.c",
                        },
                    ),
                    line: 9,
                    column: 3,
                    offset: 60,
                },
            ),
        },
    ),
]
children: Map {
    iter: Iter(
        [
            Some(
                Entity {
                    kind: TypedefDecl,
                    display_name: Some(
                        "foo",
                    ),
                    location: Some(
                        SourceLocation {
                            file: Some(
                                File {
                                    path: "test/simple.c",
                                },
                            ),
                            line: 4,
                            column: 3,
                            offset: 30,
                        },
                    ),
                },
            ),
            Some(
                Entity {
                    kind: TypedefDecl,
                    display_name: Some(
                        "foo",
                    ),
                    location: Some(
                        SourceLocation {
                            file: Some(
                                File {
                                    path: "test/simple.c",
                                },
                            ),
                            line: 4,
                            column: 3,
                            offset: 30,
                        },
                    ),
                },
            ),
            None,
            None,
            Some(
                Entity {
                    kind: FieldDecl,
                    display_name: Some(
                        "a",
                    ),
                    location: Some(
                        SourceLocation {
                            file: Some(
                                File {
                                    path: "test/simple.c",
                                },
                            ),
                            line: 3,
                            column: 9,
                            offset: 25,
                        },
                    ),
                },
            ),
            None,
            None,
            None,
            Some(
                Entity {
                    kind: StructDecl,
                    display_name: None,
                    location: Some(
                        SourceLocation {
                            file: Some(
                                File {
                                    path: "test/simple.c",
                                },
                            ),
                            line: 1,
                            column: 9,
                            offset: 8,
                        },
                    ),
                },
            ),
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            Some(
                Entity {
                    kind: TypeRef,
                    display_name: Some(
                        "foo",
                    ),
                    location: Some(
                        SourceLocation {
                            file: Some(
                                File {
                                    path: "test/simple.c",
                                },
                            ),
                            line: 8,
                            column: 3,
                            offset: 51,
                        },
                    ),
                },
            ),
            None,
            None,
            Some(
                Entity {
                    kind: CompoundStmt,
                    display_name: None,
                    location: Some(
                        SourceLocation {
                            file: Some(
                                File {
                                    path: "test/simple.c",
                                },
                            ),
                            line: 7,
                            column: 1,
                            offset: 47,
                        },
                    ),
                },
            ),
            Some(
                Entity {
                    kind: DeclRefExpr,
                    display_name: Some(
                        "f",
                    ),
                    location: Some(
                        SourceLocation {
                            file: Some(
                                File {
                                    path: "test/simple.c",
                                },
                            ),
                            line: 9,
                            column: 3,
                            offset: 60,
                        },
                    ),
                },
            ),
        ],
    ),
}

No annotated tokens

The second crazy issue showed up when I made a simple change to the C file: I made the char *a; member an integer instead. Now there are no diagnostics, but also no annotated tokens at all. The normal tokens look just fine and include identifiers for f and a in the assignment.

simple.c

typedef struct
{
  int a;
} foo;

int main()
{
  foo f;
  f.a = 0;
}

main.rs

Unchanged

stdout

tu: TranslationUnit {
    spelling: "test/simple.c",
}
diags: []
tokens: [
    Token {
        kind: Keyword,
        spelling: "typedef",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 1,
                column: 1,
                offset: 0,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 1,
                column: 8,
                offset: 7,
            },
        },
    },
    Token {
        kind: Keyword,
        spelling: "struct",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 1,
                column: 9,
                offset: 8,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 1,
                column: 15,
                offset: 14,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: "{",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 2,
                column: 1,
                offset: 15,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 2,
                column: 2,
                offset: 16,
            },
        },
    },
    Token {
        kind: Keyword,
        spelling: "int",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 3,
                column: 3,
                offset: 19,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 3,
                column: 6,
                offset: 22,
            },
        },
    },
    Token {
        kind: Identifier,
        spelling: "a",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 3,
                column: 7,
                offset: 23,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 3,
                column: 8,
                offset: 24,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: ";",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 3,
                column: 8,
                offset: 24,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 3,
                column: 9,
                offset: 25,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: "}",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 4,
                column: 1,
                offset: 26,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 4,
                column: 2,
                offset: 27,
            },
        },
    },
    Token {
        kind: Identifier,
        spelling: "foo",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 4,
                column: 3,
                offset: 28,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 4,
                column: 6,
                offset: 31,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: ";",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 4,
                column: 6,
                offset: 31,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 4,
                column: 7,
                offset: 32,
            },
        },
    },
    Token {
        kind: Keyword,
        spelling: "int",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 1,
                offset: 34,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 4,
                offset: 37,
            },
        },
    },
    Token {
        kind: Identifier,
        spelling: "main",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 5,
                offset: 38,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 9,
                offset: 42,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: "(",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 9,
                offset: 42,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 10,
                offset: 43,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: ")",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 10,
                offset: 43,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 6,
                column: 11,
                offset: 44,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: "{",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 7,
                column: 1,
                offset: 45,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 7,
                column: 2,
                offset: 46,
            },
        },
    },
    Token {
        kind: Identifier,
        spelling: "foo",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 8,
                column: 3,
                offset: 49,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 8,
                column: 6,
                offset: 52,
            },
        },
    },
    Token {
        kind: Identifier,
        spelling: "f",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 8,
                column: 7,
                offset: 53,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 8,
                column: 8,
                offset: 54,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: ";",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 8,
                column: 8,
                offset: 54,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 8,
                column: 9,
                offset: 55,
            },
        },
    },
    Token {
        kind: Identifier,
        spelling: "f",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 3,
                offset: 58,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 4,
                offset: 59,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: ".",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 4,
                offset: 59,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 5,
                offset: 60,
            },
        },
    },
    Token {
        kind: Identifier,
        spelling: "a",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 5,
                offset: 60,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 6,
                offset: 61,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: "=",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 7,
                offset: 62,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 8,
                offset: 63,
            },
        },
    },
    Token {
        kind: Literal,
        spelling: "0",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 9,
                offset: 64,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 10,
                offset: 65,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: ";",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 10,
                offset: 65,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 9,
                column: 11,
                offset: 66,
            },
        },
    },
    Token {
        kind: Punctuation,
        spelling: "}",
        range: SourceRange {
            start: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 10,
                column: 1,
                offset: 67,
            },
            end: SourceLocation {
                file: Some(
                    File {
                        path: "test/simple.c",
                    },
                ),
                line: 10,
                column: 2,
                offset: 68,
            },
        },
    },
]
annotated: [
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
    None,
]
children: Map {
    iter: Iter(
        [
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
        ],
    ),
}

Thanks for the help!

Need help: How to compile C source files

I know that it's possible to compile C source data to obj-file, or executable files with libclang.

Could you provide some practical example in rust for libclang for very basic operations that possible to do with CLI:

  • clang myfile.c -c -o myfile.o
  • clang myfile2.c myfile.o -o myapp

It will be really helpful to know how to do that with Rust using libclang.
Or to do the same things for ll files (LLVM IR source files).

Printing clang error results in infinite recursion and stack overflow

When trying to print SourceError, the program goes into infinite recursion and fails with stack overflow. In my case, I tried to print the error after unsuccessful parsing of nonexistent file.

For file:

extern crate clang;
use clang::*;

fn main() {
    let clang = Clang::new().unwrap();
    let index = Index::new(&clang, false, false);

    let _tu = index.parser("nonexistent.c").parse().unwrap();
}

â€ĻI've got the following error:

$ cargo run          
   Compiling libclang-error v0.1.0 (/home/nawordar/projects/tests/rust/libclang-error)
    Finished dev [unoptimized + debuginfo] target(s) in 0.41s
     Running `target/debug/libclang-error`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Unknown', src/main.rs:8:15
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

When I changed the code to:

extern crate clang;
use clang::*;

fn main() {
    let clang = Clang::new().unwrap();
    let index = Index::new(&clang, false, false);

    let tu = index.parser("nonexistent.c").parse();
    if let Err(err) = tu {
        println!("{}", err);
    }
}

â€ĻI had a segfault:

$ cargo run          
   Compiling libclang-error v0.1.0 (/home/nawordar/projects/tests/rust/libclang-error)
    Finished dev [unoptimized + debuginfo] target(s) in 0.41s
     Running `target/debug/libclang-error`
zsh: segmentation fault (core dumped)  cargo run

I have debugged it with gdb and it repeatedly executes line src/error.rs:66 until SIGSEGV:

$ gdb target/debug/libclang-error                                                                                          
GNU gdb (GDB) 9.2                                                                                                          
Copyright (C) 2020 Free Software Foundation, Inc.                                                                          
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>                                              
This is free software: you are free to change and redistribute it.                                                         
There is NO WARRANTY, to the extent permitted by law.                                                                      
Type "show copying" and "show warranty" for details.                                                                       
This GDB was configured as "x86_64-pc-linux-gnu".                                                                          
Type "show configuration" for configuration details.                                                                       
For bug reporting instructions, please see:                                                                                
<http://www.gnu.org/software/gdb/bugs/>.                                                                                   
Find the GDB manual and other documentation resources online at:                                                           
    <http://www.gnu.org/software/gdb/documentation/>.                                                                      
                                                                                                                           
For help, type "help".                                                                                                     
Type "apropos word" to search for commands related to "word"...                                                            
Reading symbols from target/debug/libclang-error...                                                                        
warning: Missing auto-load script at offset 0 in section .debug_gdb_scripts                                                
of file /home/nawordar/projects/tests/rust/libclang-error/target/debug/libclang-error.                                     
Use `info auto-load python-scripts [REGEXP]' to list them.                                                                 
(gdb) r                                                                                                                    
Starting program: /home/nawordar/projects/tests/rust/libclang-error/target/debug/libclang-error                            
[Thread debugging using libthread_db enabled]                                                                              
Using host libthread_db library "/usr/lib/libthread_db.so.1".                                                              
[New Thread 0x7fffee01e640 (LWP 86175)]                                                                                    
[Thread 0x7fffee01e640 (LWP 86175) exited]                                                                                 
                                                                                                                           
Thread 1 "libclang-error" received signal SIGSEGV, Segmentation fault.                                                     
core::fmt::write () at src/libcore/fmt/mod.rs:1060                                                                         
1060    src/libcore/fmt/mod.rs: No such file or directory.                                                                 
(gdb) backtrace                                                                                                            
#0  core::fmt::write () at src/libcore/fmt/mod.rs:1060                                                                     
#1  0x000055555558a774 in core::fmt::Formatter::write_fmt () at src/libcore/fmt/mod.rs:1505                                
#2  0x000055555555cfca in <clang::error::SourceError as core::fmt::Display>::fmt (self=0x7fffffffdbb7,                     
    formatter=0x7fffff7ff150)                                                                                              
    at /home/nawordar/.cargo/registry/src/github.com-1ecc6299db9ec823/clang-1.0.1/src/error.rs:66                          
#3  0x000055555555ceb7 in <&T as core::fmt::Display>::fmt (self=0x7fffff7ff248, f=0x7fffff7ff150)                          
    at /home/nawordar/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/fmt/mod.rs:1981
#4  0x0000555555589b1c in core::fmt::write () at src/libcore/fmt/mod.rs:1076
#5  0x000055555558a774 in core::fmt::Formatter::write_fmt () at src/libcore/fmt/mod.rs:1505
#6  0x000055555555cfca in <clang::error::SourceError as core::fmt::Display>::fmt (self=0x7fffffffdbb7, 
    formatter=0x7fffff7ff2e0)
    at /home/nawordar/.cargo/registry/src/github.com-1ecc6299db9ec823/clang-1.0.1/src/error.rs:66
#7  0x000055555555ceb7 in <&T as core::fmt::Display>::fmt (self=0x7fffff7ff3d8, f=0x7fffff7ff2e0)
    at /home/nawordar/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/fmt/mod.rs:1981
#8  0x0000555555589b1c in core::fmt::write () at src/libcore/fmt/mod.rs:1076
#9  0x000055555558a774 in core::fmt::Formatter::write_fmt () at src/libcore/fmt/mod.rs:1505
#10 0x000055555555cfca in <clang::error::SourceError as core::fmt::Display>::fmt (self=0x7fffffffdbb7, 
    formatter=0x7fffff7ff470)
    at /home/nawordar/.cargo/registry/src/github.com-1ecc6299db9ec823/clang-1.0.1/src/error.rs:66
#11 0x000055555555ceb7 in <&T as core::fmt::Display>::fmt (self=0x7fffff7ff568, f=0x7fffff7ff470)
    at /home/nawordar/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/fmt/mod.rs:1981
#12 0x0000555555589b1c in core::fmt::write () at src/libcore/fmt/mod.rs:1076
#13 0x000055555558a774 in core::fmt::Formatter::write_fmt () at src/libcore/fmt/mod.rs:1505
#14 0x000055555555cfca in <clang::error::SourceError as core::fmt::Display>::fmt (self=0x7fffffffdbb7, 
    formatter=0x7fffff7ff600)
    at /home/nawordar/.cargo/registry/src/github.com-1ecc6299db9ec823/clang-1.0.1/src/error.rs:66
#15 0x000055555555ceb7 in <&T as core::fmt::Display>::fmt (self=0x7fffff7ff6f8, f=0x7fffff7ff600)
    at /home/nawordar/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/fmt/mod.rs:1981
#16 0x0000555555589b1c in core::fmt::write () at src/libcore/fmt/mod.rs:1076
#17 0x000055555558a774 in core::fmt::Formatter::write_fmt () at src/libcore/fmt/mod.rs:1505
#18 0x000055555555cfca in <clang::error::SourceError as core::fmt::Display>::fmt (self=0x7fffffffdbb7, 
    formatter=0x7fffff7ff790)
    at /home/nawordar/.cargo/registry/src/github.com-1ecc6299db9ec823/clang-1.0.1/src/error.rs:66
#19 0x000055555555ceb7 in <&T as core::fmt::Display>::fmt (self=0x7fffff7ff888, f=0x7fffff7ff790)
    at /home/nawordar/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/fmt/mod.rs:1981
#20 0x0000555555589b1c in core::fmt::write () at src/libcore/fmt/mod.rs:1076
#21 0x000055555558a774 in core::fmt::Formatter::write_fmt () at src/libcore/fmt/mod.rs:1505
#22 0x000055555555cfca in <clang::error::SourceError as core::fmt::Display>::fmt (self=0x7fffffffdbb7, 
    formatter=0x7fffff7ff920)
    at /home/nawordar/.cargo/registry/src/github.com-1ecc6299db9ec823/clang-1.0.1/src/error.rs:66
#23 0x000055555555ceb7 in <&T as core::fmt::Display>::fmt (self=0x7fffff7ffa18, f=0x7fffff7ff920)
    at /home/nawordar/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/fmt/mod.rs:1981
#24 0x0000555555589b1c in core::fmt::write () at src/libcore/fmt/mod.rs:1076
#25 0x000055555558a774 in core::fmt::Formatter::write_fmt () at src/libcore/fmt/mod.rs:1505
#26 0x000055555555cfca in <clang::error::SourceError as core::fmt::Display>::fmt (self=0x7fffffffdbb7, 
    formatter=0x7fffff7ffab0)
    at /home/nawordar/.cargo/registry/src/github.com-1ecc6299db9ec823/clang-1.0.1/src/error.rs:66
#27 0x000055555555ceb7 in <&T as core::fmt::Display>::fmt (self=0x7fffff7ffba8, f=0x7fffff7ffab0)
    at /home/nawordar/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/fmt/mod.rs:1981
#28 0x0000555555589b1c in core::fmt::write () at src/libcore/fmt/mod.rs:1076

can not visit FriendDecl and CXXAccessSpecifier

the input c++ class is :

// file: example/structs.hpp
#include <tuple>
class foo
{
	public:
		foo(int n_, char c_, double d_)
			: n{n_}, c{c_}, d{d_}
		{}
		friend bool operator<(const foo& lh, const foo& rh)
		{
			return std::tie(lh.n, lh.c, lh.d) <
			       std::tie(rh.n, rh.c, rh.d);
		}
	private:
		int n;
		char c;
		double d;
};

the visit program is:

use clang::*;

fn main() {
    // Acquire an instance of `Clang`
    let clang = Clang::new().unwrap();

    // Create a new `Index`
    let index = Index::new(&clang, false, false);

    // Parse a source file into a translation unit
    let tu = index.parser("examples/structs.hpp").parse().unwrap();

    // Get the class in this translation unit
    let classes = tu
        .get_entity()
        .get_children()
        .into_iter()
        .filter(|e| e.get_kind() == EntityKind::ClassDecl)
        .collect::<Vec<_>>();

    for cls in classes {
        visit_entity(cls, 0);
    }
}

fn visit_entity(e: Entity, lev: usize) {
    if let Some(t) = e.get_type() {
        println!(
            "{spaces}{k:?} {n:?} ",
            spaces = (0..lev).map(|_| "-").collect::<String>(),
            k = e.get_kind(),
            n = e.get_name().unwrap_or_default()
        );

        for f in e.get_children() {
            visit_entity(f, lev + 1)
        }
    }
}

the really output is:

ClassDecl "foo" 
-Constructor "foo" 
--ParmDecl "n_"
--ParmDecl "c_"
--ParmDecl "d_"
--MemberRef "n"
--InitListExpr ""
---UnexposedExpr "n_"
----DeclRefExpr "n_"
--MemberRef "c"
--InitListExpr ""
---UnexposedExpr "c_"
----DeclRefExpr "c_"
--MemberRef "d"
--InitListExpr ""
---UnexposedExpr "d_"
----DeclRefExpr "d_" 
-FieldDecl "n"
-FieldDecl "c"
-FieldDecl "d"

Windows 10 Build Failing

Hello,

Thanks for this project. I am trying to use it on windows, but none the test pass because I get the following error:

thread 'test' panicked at 'a `libclang` shared library is not loaded on this thread', src\libcore\option.rs:1038:5

I updated Cargo.toml for clang-sys to use the master branch since those tests pass.

clang-sys = { git="https://github.com/KyleMayes/clang-sys.git", branch="master", features = ["runtime", "clang_6_0"] }

What is extra strange is that clang-sys on its own passes both the tests:

C:\Users\dev\Projects\clang-sys>cargo test
    Finished dev [unoptimized + debuginfo] target(s) in 0.04s
     Running target\debug\deps\clang_sys-ae7cfce2797a2aee.exe

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target\debug\deps\lib-fca0a27cb6a671d0.exe

running 2 tests
test test ... ok
test test_support ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests clang-sys

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

Here is my clang version:

C:\Users\dev\Projects\clang-rs>clang --version
clang version 6.0.0 (tags/RELEASE_600/final)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin

I am using Microsoft Windows 10 Pro.

obtain the const type

Hey,
Is there a way to obtain the inside type of a const type.
I know in the api I can invoke.

type_.is_const_qualified()

but how can I obtain the type that is const qualified?

For example if I have a type that is:

const int

is there a way to get hold of:

int

Entity.get_platform_availability() crashing on double free

When trying to call Entity.get_platform_availability(), my program crashes with the following message:

malloc: *** error for object 0x100704370: pointer being freed was not allocated

Looking at the stack track in the debugger it happens inside clang_disposeCXPlatformAvailability.
Having a look at the clang source code, clang_disposeCXPlatformAvailability is pretty simple:

void clang_disposeCXPlatformAvailability(CXPlatformAvailability *availability) {
  clang_disposeString(availability->Platform);
  clang_disposeString(availability->Message);
}

It seems at least one of the strings has been freed somewhere else.
And looking a bit more at the clang-rs source they are indeed already freed when converted to Rust string:

impl PlatformAvailability {
    fn from_raw(mut raw: CXPlatformAvailability) -> PlatformAvailability {
        let availability = PlatformAvailability {
            platform: utility::to_string(raw.Platform),
            unavailable: raw.Unavailable != 0,
            introduced: raw.Introduced.map(Version::from_raw),
            deprecated: raw.Deprecated.map(Version::from_raw),
            obsoleted: raw.Obsoleted.map(Version::from_raw),
            message: utility::to_string_option(raw.Message),
        };
        unsafe { clang_disposeCXPlatformAvailability(&mut raw); }
        availability
    }
}

with utility::to_string being:

pub fn to_string(clang: CXString) -> String {
    unsafe {
        let c = CStr::from_ptr(clang_getCString(clang));
        let rust = c.to_str().expect("invalid Rust string").into();
        clang_disposeString(clang);
        rust
    }
}

I'm not sure it is the best fix but I guess removing the call to clang_disposeCXPlatformAvailability would fix the crash?

clang::source::SourceRange::tokenize can construct a slice with a null pointer, which is UB

This is detectable through the standard library's debug assertions, which are currently only usable on a nightly compiler with -Zbuild-std, or if you build your own compiler and standard library with them enabled. That's what was done in the crater run which yielded this build log: https://crater-reports.s3.amazonaws.com/pr-101929/try%233bbb5242a8064de4ca3af4036745ddf603ddaa85/reg/printimg-0.5.5/log.txt among many others.

The problem (if it exists) is in this code:

clang-rs/src/source.rs

Lines 447 to 449 in 79f83c7

clang_tokenize(self.tu.ptr, self.raw, raw.as_mut_ptr(), count.as_mut_ptr());
let (raw, count) = (raw.assume_init(), count.assume_init());
let raws = slice::from_raw_parts(raw, count as usize);

It's not uncommon for C APIs to return a null pointer and 0 length (font-kit has made the same mistake), but in Rust it's not valid to construct a slice from a null pointer, because slice::from_raw_parts actually returns a reference and references must not be null.

Here is the top of a backtrace from a core dump from one of many crates which depend on opencv, whose build process depends on version 1 of this crate:

#0  core::slice::raw::from_raw_parts::runtime<clang_sys::CXToken> () at /home/ben/rust/library/core/src/slice/raw.rs:93
#1  core::slice::raw::from_raw_parts<clang_sys::CXToken> (data=0x0, len=0)
    at /home/ben/rust/library/core/src/intrinsics.rs:2195
#2  0x0000557e09566b31 in clang::source::SourceRange::tokenize (self=0x7fabfb1ef0f0) at src/source.rs:449
#3  0x0000557e0932c838 in opencv_binding_generator::field::Field::default_value (self=0x7fabfb1ef320) at src/field.rs:98
#4  0x0000557e0933380a in opencv_binding_generator::func::{impl#5}::rendered_doc_comment_with_prefix::{closure#1} (
    out=0x7fabfb1ef638) at src/func.rs:609

I'd be submitting a patch, but one thing here is odd: I can only find these null slices from crates which use version 1 of this crate. Perhaps version 2 is just not used very much yet (it is surely used much less than clang-rs version 1, by about a factor of 9). Or maybe this bug doesn't come up because of some subtle change elsewhere in this library. I'm just not sure, but the fact that the code linked above doesn't check for null is suspicious.

Help wanted: get macro value

I have spent several hours, but can't find solution. Please help..

I have some macro in header file like:
#define SomeThing '1'

in Rust I have these code:

let clang = Clang::new().unwrap();
let index = Index::new(&clang, false, false);

let tu = index.parser("file_path")
            .arguments(&["-x", "c++"])
            .detailed_preprocessing_record(true) // for macro
            .parse()
            .unwrap();

let children = tu.get_entity().get_children().into_iter();

for cursor in children {
	match cursor.get_kind() {
		EntityKind::MacroDefinition => {
			 // I can get macro name here, but can't get macro value.
		}
	}
}

in
https://stackoverflow.com/questions/10113586/how-can-i-parse-macros-in-c-code-using-clang-as-the-parser-and-python-as-the

the solution for python:
tu = index.parse(sys.argv[1], options=clang.cindex.TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD)

def visit(node):
    if node.kind in (clang.cindex.CursorKind.MACRO_INSTANTIATION, clang.cindex.CursorKind.MACRO_DEFINITION):
        print 'Found %s Type %s DATA %s Extent %s [line=%s, col=%s]' % (node.displayname, node.kind, node.data, node.extent, node.location.line, node.location.column)
    for c in node.get_children():
        visit(c)

but I can't find some method like "node.data" in clang-rs.

A few renaming suggestions

Hey, thanks a lot for making this library, it's great!

When you get around to releasing a new version, may I suggest the following?

  • A lot of methods use the get_ prefix, which is generally discouraged in Rust (source); so instead of e.g. get_name(), just use name().
  • It was confusing to me at first that "entity" means "cursor", so I'd either rename the Entity struct to Cursor, to match the original bindings, or at least document it.

Of course, if there's reasons for not doing these, then by all means do so, just wanted to note the few gripes I had.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤ī¸ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.