]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/debuginfo/create_scope_map.rs
Fix invalid associated type rendering in rustdoc
[rust.git] / src / librustc_trans / debuginfo / create_scope_map.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use super::FunctionDebugContext;
12 use super::metadata::file_metadata;
13 use super::utils::{DIB, span_start};
14
15 use llvm;
16 use llvm::debuginfo::{DIScope, DISubprogram};
17 use common::CrateContext;
18 use rustc::mir::{Mir, VisibilityScope};
19
20 use libc::c_uint;
21 use std::ptr;
22
23 use syntax_pos::Pos;
24
25 use rustc_data_structures::bitvec::BitVector;
26 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
27
28 use syntax_pos::BytePos;
29
30 #[derive(Clone, Copy, Debug)]
31 pub struct MirDebugScope {
32     pub scope_metadata: DIScope,
33     // Start and end offsets of the file to which this DIScope belongs.
34     // These are used to quickly determine whether some span refers to the same file.
35     pub file_start_pos: BytePos,
36     pub file_end_pos: BytePos,
37 }
38
39 impl MirDebugScope {
40     pub fn is_valid(&self) -> bool {
41         !self.scope_metadata.is_null()
42     }
43 }
44
45 /// Produce DIScope DIEs for each MIR Scope which has variables defined in it.
46 /// If debuginfo is disabled, the returned vector is empty.
47 pub fn create_mir_scopes(ccx: &CrateContext, mir: &Mir, debug_context: &FunctionDebugContext)
48     -> IndexVec<VisibilityScope, MirDebugScope> {
49     let null_scope = MirDebugScope {
50         scope_metadata: ptr::null_mut(),
51         file_start_pos: BytePos(0),
52         file_end_pos: BytePos(0)
53     };
54     let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes);
55
56     let fn_metadata = match *debug_context {
57         FunctionDebugContext::RegularContext(ref data) => data.fn_metadata,
58         FunctionDebugContext::DebugInfoDisabled |
59         FunctionDebugContext::FunctionWithoutDebugInfo => {
60             return scopes;
61         }
62     };
63
64     // Find all the scopes with variables defined in them.
65     let mut has_variables = BitVector::new(mir.visibility_scopes.len());
66     for var in mir.vars_iter() {
67         let decl = &mir.local_decls[var];
68         has_variables.insert(decl.source_info.unwrap().scope.index());
69     }
70
71     // Instantiate all scopes.
72     for idx in 0..mir.visibility_scopes.len() {
73         let scope = VisibilityScope::new(idx);
74         make_mir_scope(ccx, &mir, &has_variables, fn_metadata, scope, &mut scopes);
75     }
76
77     scopes
78 }
79
80 fn make_mir_scope(ccx: &CrateContext,
81                   mir: &Mir,
82                   has_variables: &BitVector,
83                   fn_metadata: DISubprogram,
84                   scope: VisibilityScope,
85                   scopes: &mut IndexVec<VisibilityScope, MirDebugScope>) {
86     if scopes[scope].is_valid() {
87         return;
88     }
89
90     let scope_data = &mir.visibility_scopes[scope];
91     let parent_scope = if let Some(parent) = scope_data.parent_scope {
92         make_mir_scope(ccx, mir, has_variables, fn_metadata, parent, scopes);
93         scopes[parent]
94     } else {
95         // The root is the function itself.
96         let loc = span_start(ccx, mir.span);
97         scopes[scope] = MirDebugScope {
98             scope_metadata: fn_metadata,
99             file_start_pos: loc.file.start_pos,
100             file_end_pos: loc.file.end_pos,
101         };
102         return;
103     };
104
105     if !has_variables.contains(scope.index()) {
106         // Do not create a DIScope if there are no variables
107         // defined in this MIR Scope, to avoid debuginfo bloat.
108
109         // However, we don't skip creating a nested scope if
110         // our parent is the root, because we might want to
111         // put arguments in the root and not have shadowing.
112         if parent_scope.scope_metadata != fn_metadata {
113             scopes[scope] = parent_scope;
114             return;
115         }
116     }
117
118     let loc = span_start(ccx, scope_data.span);
119     let file_metadata = file_metadata(ccx, &loc.file.name, &loc.file.abs_path);
120     let scope_metadata = unsafe {
121         llvm::LLVMRustDIBuilderCreateLexicalBlock(
122             DIB(ccx),
123             parent_scope.scope_metadata,
124             file_metadata,
125             loc.line as c_uint,
126             loc.col.to_usize() as c_uint)
127     };
128     scopes[scope] = MirDebugScope {
129         scope_metadata: scope_metadata,
130         file_start_pos: loc.file.start_pos,
131         file_end_pos: loc.file.end_pos,
132     };
133 }