~siretart/aspectc++/debian

« back to all changes in this revision

Viewing changes to AspectC++/WeaverBase.cc

  • Committer: Reinhard Tartler
  • Date: 2013-10-13 18:22:49 UTC
  • mfrom: (1.2.8)
  • Revision ID: siretart@tauware.de-20131013182249-fv725vy5ikslptpj
new upstream relesae

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
 
24
24
// PUMA includes
25
25
#include "Puma/ErrorSink.h"
26
 
#include "Puma/CFunctionInfo.h"
27
 
#include "Puma/CArgumentInfo.h"
28
 
#include "Puma/CClassInfo.h"
29
 
#include "Puma/CTemplateInfo.h"
30
 
#include "Puma/CTemplateInstance.h"
31
26
#include "Puma/CTree.h"
32
27
#include "Puma/MacroUnit.h"
33
28
 
34
 
// C++ includes
35
 
#include <sstream>
36
 
using std::stringstream;
37
 
using std::endl;
38
 
#include <cstring>
39
 
using std::strstr;
40
 
 
41
29
const WeavePos &WeaverBase::weave_pos (Token *t, WeavePos::Pos p) {
42
30
 
43
 
  // try to insert the position as a new one
44
 
  pair<WPSet::iterator, bool> result = _positions.insert (WeavePos (t, p));
45
 
 
46
 
  // the resulting iterator points either to the new or an existing entry
 
31
  // check whether the weaving position has already been created
 
32
  WPSet::iterator i = _positions.find (WeavePos (t, p));
 
33
  if (i != _positions.end ())
 
34
    return *i;
 
35
 
 
36
  // create an insert a marker token
 
37
  Token *marker_token = new Token; // just a marker token without text etc.
 
38
  marker_token->location (t->location ());
 
39
  Unit *marker_unit = new Unit;
 
40
  marker_unit->append (*marker_token);
 
41
  _commander.addBuffer (marker_unit);
 
42
  if (p == WeavePos::WP_HEADER) {
 
43
    // check whether there is already a marker token in front of the first token
 
44
    Token *marker_inspos = t;
 
45
    WPSet::iterator i = _positions.find (WeavePos (t, WeavePos::WP_BEFORE));
 
46
    if (i != _positions.end ())
 
47
      marker_inspos = (*i)._marker;
 
48
    _commander.move_before (marker_token, marker_token, marker_inspos);
 
49
  }
 
50
  else if (p == WeavePos::WP_BEFORE)
 
51
    _commander.move_before (marker_token, marker_token, t);
 
52
  else if (p == WeavePos::WP_FOOTER) {
 
53
    // check whether there is already a marker token behind the last token
 
54
    Token *marker_inspos = t;
 
55
    WPSet::iterator i = _positions.find (WeavePos (t, WeavePos::WP_AFTER));
 
56
    if (i != _positions.end ())
 
57
      marker_inspos = (*i)._marker;
 
58
    _commander.move (marker_token, marker_token, marker_inspos);
 
59
  }
 
60
  else
 
61
    _commander.move (marker_token, marker_token, t);
 
62
 
 
63
  // insert the position as a new one
 
64
  pair<WPSet::iterator, bool> result =
 
65
      _positions.insert (WeavePos (t, p, marker_token));
 
66
 
 
67
  // the resulting iterator points to the new entry
47
68
  return *result.first;
48
69
}
49
70
 
50
 
// insert the contents of a generated unit at a given position (with move)
51
 
void WeaverBase::paste (const WeavePos &pos, Unit *unit) {
 
71
// get the 'header' weaving position in front of a unit
 
72
const WeavePos &WeaverBase::header_pos (Unit *unit) {
 
73
  Token *first = (Token*)unit->first ();
 
74
  if (unit == (Unit*)_primary_start->belonging_to ())
 
75
    first = _primary_start;
 
76
  return weave_pos (first, WeavePos::WP_HEADER);
 
77
}
 
78
 
 
79
// get the 'header' weaving position in front of the primary unit
 
80
const WeavePos &WeaverBase::header_pos () {
 
81
  return weave_pos (_primary_start, WeavePos::WP_HEADER);
 
82
}
 
83
 
 
84
// get the 'footer' weaving position at the end of an arbitrary unit
 
85
const WeavePos &WeaverBase::footer_pos (Unit *unit) {
 
86
  Token *last = (Token*)unit->last ();
 
87
  if (unit == (Unit*)_primary_end->belonging_to ())
 
88
    last = _primary_end;
 
89
  return weave_pos (last, WeavePos::WP_FOOTER);
 
90
}
 
91
 
 
92
// get the 'footer' weaving position at the end of the primary unit
 
93
const WeavePos &WeaverBase::footer_pos () {
 
94
  return weave_pos (_primary_end, WeavePos::WP_FOOTER);
 
95
}
 
96
 
 
97
// insert a unit at the specified weaving position
 
98
// 'before' selects whether the new text is inserted either before (true)
 
99
// or after (false) any text that has been inserted earlier at this position.
 
100
void WeaverBase::insert (const WeavePos &pos, Unit *unit, bool before) {
52
101
  // return immediately if the there is a problem with macro manipulation
53
102
  if (macro_problem (pos))
54
103
    return;
55
104
 
56
 
  Token *tok = pos._token;
57
 
//  if (tok->unit ()->isMacroExp ()) {
58
 
//    MacroUnit *munit = (MacroUnit*)tok->unit ();
59
 
//    if (tok == munit->first() && pos._pos == WeavePos::WP_BEFORE)
60
 
//      tok = munit->ExpansionBegin(tok);
61
 
//    else if (tok == munit->last() && pos._pos == WeavePos::WP_AFTER)
62
 
//      tok = munit->ExpansionEnd(tok);
63
 
//  }
64
 
  _commander.addBuffer (unit);
65
 
  Token *first = (Token*)unit->first ();
66
 
  Token *last  = (Token*)unit->last ();
67
 
  if (pos._pos == WeavePos::WP_BEFORE) {
68
 
    _commander.move_before (first, last, tok);
69
 
  }
70
 
  else {
71
 
    _commander.move (first, last, tok);
72
 
  }
 
105
  // store the unit in the right order for insertion (later when committing)
 
106
  if (before)
 
107
    pos._units.push_front(unit);
 
108
  else
 
109
    pos._units.push_back(unit);
73
110
}
74
111
 
75
 
// insert a generated string a given position
76
 
void WeaverBase::paste (const WeavePos &pos, const string &str) {
 
112
// the same as the other 'insert' method (above), but converts string to unit
 
113
void WeaverBase::insert (const WeavePos &pos, const string &str, bool before) {
77
114
  // return immediately if the string to paste is empty
78
115
  if (str == "")
79
116
    return;
80
117
 
81
118
  ACUnit *unit = new ACUnit (_err);
82
 
  bool has_nl = (strstr (str.c_str (), "\n") != NULL);
 
119
  bool has_nl = (str.find('\n') != string::npos);
83
120
  if (has_nl)
84
121
    _line_mgr.directive (*unit);
85
122
  *unit << str.c_str ();
86
123
  if (has_nl)
87
124
    _line_mgr.directive (*unit, (Unit*)pos._token->belonging_to (), pos._token);
88
125
  *unit << endu;
89
 
  paste (pos, unit);
90
 
}
91
 
 
92
 
// insert a generated string at the beginning of a unit
93
 
// The implementation makes sure that all pasted tokens will appear after the
94
 
// transformation in front of tokens that were pasted ahead of the first token
95
 
void WeaverBase::paste_first (Unit *unit, const string  &str) {
96
 
  UnitTokenMap::iterator i = _start_token_map.find (unit);
97
 
  Token *start_token = 0;
98
 
  if (i != _start_token_map.end ()) {
99
 
        start_token = i->second;
100
 
  }
101
 
  else {
102
 
    start_token = new Token; // just a marker token without text etc.
103
 
    Token *first = (Token*)unit->first ();
104
 
    if (unit == (Unit*)_primary_start->belonging_to ())
105
 
      first = _primary_start;
106
 
    start_token->location (first->location ());
107
 
    List marker;
108
 
    marker.append (*start_token);
109
 
    unit->move_before (first, marker);
110
 
    _start_token_map.insert (UnitTokenMap::value_type (unit, start_token));
111
 
  }
112
 
  paste (weave_pos (start_token, WeavePos::WP_BEFORE), str);
113
 
}
114
 
 
115
 
// insert the contents of a generated unit at the end of the translation
116
 
// unit (with move)
117
 
void WeaverBase::paste_end (Unit *unit) {
118
 
 
119
 
  // this is our position ...
120
 
  const WeavePos &pos = weave_pos (_primary_end, WeavePos::WP_AFTER);
121
 
 
122
 
  // return immediately if the there is a problem with macro manipulation
123
 
  if (macro_problem (pos))
124
 
    return;
125
 
 
126
 
  _commander.addBuffer (unit);
127
 
  Token *first = (Token*)unit->first ();
128
 
  Token *last  = (Token*)unit->last ();
129
 
  _commander.move (first, last, pos._token);
130
 
}
131
 
 
132
 
// insert a generated string at the end of the translation unit (with move)
133
 
void WeaverBase::paste_end (const string &str) {
134
 
  // return immediately if the string to paste is empty
135
 
  if (str == "")
136
 
    return;
137
 
 
138
 
  ACUnit *unit = new ACUnit (_err);
139
 
  bool has_nl = (strstr (str.c_str (), "\n") != NULL);
140
 
  if (has_nl)
141
 
    _line_mgr.directive (*unit);
142
 
  *unit << str.c_str ();
143
 
  if (has_nl)
144
 
    _line_mgr.directive (*unit, (Unit*)_primary_end->belonging_to (), _primary_end);
145
 
  *unit << endu;
146
 
  paste_end (unit);
147
 
}
 
126
  insert (pos, unit, before);
 
127
}
 
128
 
148
129
 
149
130
// replace the text between two positions with some new text
150
131
void WeaverBase::replace (const WeavePos &from, const WeavePos &to,
151
132
                                             const string &str) {
152
 
  paste (from, str);
 
133
  insert (from, str);
153
134
  kill (from, to);
154
135
}
155
136
 
156
 
// replace the text of a syntax tree with some new text
157
 
void WeaverBase::replace (CTree *node, const string &str) {
158
 
  const WeavePos &from = weave_pos (node->token (), WeavePos::WP_BEFORE);
159
 
  const WeavePos &to   = weave_pos (node->end_token (), WeavePos::WP_AFTER);
160
 
  replace (from, to, str);
161
 
}
162
137
 
163
138
// check whether two tokens are on the same line of the same unit
164
139
bool same_line (Token *t1, Token *t2, bool check_end_of_t1) {
171
146
  return (l1 == l2);
172
147
}
173
148
 
174
 
// copy the text between two position to another location
175
 
void WeaverBase::copy (const WeavePos &from, const WeavePos &to,
176
 
                       const WeavePos &dest) {
177
 
  assert (from._pos == WeavePos::WP_BEFORE);
178
 
  assert (to._pos == WeavePos::WP_AFTER);
179
 
  if (macro_problem (from) || macro_problem (to) || macro_problem (dest))
180
 
    return;
181
 
 
182
 
  if (dest._pos == WeavePos::WP_BEFORE) {
183
 
    {
184
 
      ACUnit *unit = new ACUnit (_err);
185
 
      _line_mgr.directive (*unit,
186
 
        (Unit*)from._token->belonging_to (), from._token);
187
 
      *unit << endu;
188
 
      if (unit->empty ()) delete unit; else paste (dest, unit);
189
 
    }
190
 
    _commander.copy_before (from._token, to._token, dest._token);
191
 
    {
192
 
      ACUnit *unit = new ACUnit (_err);
193
 
      _line_mgr.directive (*unit,
194
 
        (Unit*)dest._token->belonging_to (), dest._token);
195
 
      *unit << endu;
196
 
      if (unit->empty ()) delete unit; else paste (dest, unit);
197
 
    }
198
 
  }
199
 
  else {
200
 
    if (!same_line (from._token, to._token, false)) {
201
 
      ACUnit *unit = new ACUnit (_err);
202
 
      _line_mgr.directive (*unit,
203
 
        (Unit*)dest._token->belonging_to (), dest._token);
204
 
      *unit << endu;
205
 
      if (unit->empty ()) delete unit; else paste (dest, unit);
206
 
    }
207
 
    _commander.copy (from._token, to._token, dest._token);
208
 
    if (!same_line (dest._token, from._token, true)) {
209
 
      ACUnit *unit = new ACUnit (_err);
210
 
      _line_mgr.directive (*unit,
211
 
        (Unit*)from._token->belonging_to (), from._token);
212
 
      *unit << endu;
213
 
      if (unit->empty ()) delete unit; else paste (dest, unit);
214
 
    }
215
 
  }
216
 
}
217
 
 
218
 
// copy the text of a syntax tree to another location
219
 
void WeaverBase::copy (CTree *node, const WeavePos &dest) {
220
 
  const WeavePos &from = weave_pos (node->token (), WeavePos::WP_BEFORE);
221
 
  const WeavePos &to   = weave_pos (node->end_token (), WeavePos::WP_AFTER);
222
 
  copy (from, to, dest);
223
 
}
224
149
 
225
150
// kill the text between two positions
226
151
void WeaverBase::kill (const WeavePos &from, const WeavePos &to) {
230
155
  if (macro_problem (from) || macro_problem (to))
231
156
    return;
232
157
 
233
 
  bool has_nl = (strstr (from._token->text (), "\n") != NULL);
 
158
  // TODO: why is only the first token checked?
 
159
  bool has_nl = (string (from._token->text ()).find('\n') != string::npos);
234
160
  if ((to._token && from._token != to._token) || has_nl)
235
161
    _line_mgr.insert ((Unit*)to._token->belonging_to (), to._token, true);
236
162
  _commander.kill (from._token, to._token);
244
170
}
245
171
 
246
172
bool WeaverBase::commit () {
 
173
  // handle code that has to be inserted at weaving positions
 
174
  for (WPSet::iterator i = _positions.begin (); i != _positions.end (); ++i) {
 
175
    const WeavePos &wp = *i;
 
176
    for (list<Unit*>::iterator ui = wp._units.begin (); ui != wp._units.end (); ++ui) {
 
177
      Unit *unit = *ui;
 
178
      // TODO: handle line directives here (to avoid too many of them)
 
179
      _commander.addBuffer (unit);
 
180
      Token *first = (Token*)unit->first ();
 
181
      Token *last  = (Token*)unit->last ();
 
182
      // "move_before" preserves the order
 
183
      _commander.move_before (first, last, wp._marker);
 
184
    }
 
185
  }
 
186
 
247
187
  ManipError terror = _commander.valid ();
248
188
  if (!terror)
249
189
    _commander.commit ();
250
190
  else
251
191
    _err << terror << endMessage;
252
192
 
253
 
  // delete the artificially inserted unit start markers that are needed
254
 
  // by paste_first
255
 
  for (UnitTokenMap::iterator i = _start_token_map.begin ();
256
 
    i != _start_token_map.end (); ++i) {
257
 
    i->first->kill (i->second);
258
 
  }
 
193
  // clear the list of weaving positions used for this transaction
 
194
  _positions.clear();
 
195
 
259
196
  return (bool)terror;
260
197
}
261
198
 
268
205
        unit->isMacroExp () && !((MacroUnit*)unit)->ExpansionBegin (token)) ||
269
206
       (pos._pos == WeavePos::WP_AFTER &&
270
207
           unit->isMacroExp () && !((MacroUnit*)unit)->ExpansionEnd (token)))) {
271
 
      if (_problems._warn_macro) {
 
208
      if (_warn_macro_expansion) {
272
209
        _err << sev_warning << token->location ()
273
210
             << "transformation within macro '"
274
211
             << ((MacroUnit*)unit)->MacroBegin ()->text () << "'" << endMessage;
279
216
  return false;
280
217
}
281
218
 
282
 
bool WeaverBase::kill_macro_problem (CTree *tree) {
283
 
  Token *start = tree->token();
284
 
  Token *end = tree->end_token();
285
 
  if (start->unit () != end->unit())
286
 
    return true;
287
 
  if (start->unit()->isMacroExp ()) {
288
 
    start = ((MacroUnit*)start->unit())->ExpansionBegin (start);
289
 
    end   = ((MacroUnit*)end->unit())->ExpansionEnd (end);
290
 
    if (!start || !end)
291
 
      return true;
292
 
  }
293
 
  return false;
294
 
}
295
 
string WeaverBase::protection_string (CProtection::Type prot) {
296
 
  switch (prot) {
297
 
  case CProtection::PROT_PRIVATE:   return "\nprivate:\n";
298
 
  case CProtection::PROT_PROTECTED: return "\nprotected:\n";
299
 
  case CProtection::PROT_PUBLIC:    return "\npublic:\n";
300
 
  default:
301
 
    assert (false);
302
 
    return "";
303
 
  }
304
 
}
305
 
 
306
 
bool WeaverBase::needs_this (CFunctionInfo *func)
307
 
 {
308
 
  // check if the called function is a method (needs a 'this' pointer)
309
 
  if (func->isMethod () && !func->isStaticMethod ())
310
 
   {
311
 
     return !(func->isOperator () &&
312
 
              (strcmp (func->Name (), "operator new") == 0 ||
313
 
               strcmp (func->Name (), "operator new[]") == 0 ||
314
 
               strcmp (func->Name (), "operator delete") == 0 ||
315
 
               strcmp (func->Name (), "operator delete[]") == 0));
316
 
   }
317
 
  return false;
318
 
 }
319
 
 
320
 
void WeaverBase::print_tree (ostream &out, CTree *node)
321
 
 {
322
 
   if (node->NodeName () == CT_Token::NodeId ())
323
 
     out << node->token ()->text () << " ";
324
 
   else
325
 
      for (int s = 0; s < node->Sons (); s++)
326
 
         print_tree (out, node->Son (s));
327
 
 }
328
 
 
329
 
CClassInfo *WeaverBase::cscope(CObjectInfo *obj) {
330
 
  CRecord *crec = obj->ClassScope ();
331
 
  return crec ? crec->ClassInfo () : (CClassInfo*)0;
332
 
}
333
 
 
334
 
string WeaverBase::cleanup_name(const string& in) {
335
 
  string result = in;
336
 
  string::size_type pos = result.length ();
337
 
  while ((pos = result.rfind ("::<unnamed>", pos)) != string::npos)
338
 
    result = result.erase (pos, 11);
339
 
  if (result.find ("<unnamed>") == 0)
340
 
    result = result.erase (0, 9);
341
 
  return result;
342
 
}
343
 
 
344
 
CScopeInfo *WeaverBase::nscope(CObjectInfo *obj) {
345
 
  // template instances are stored in a special scope, better take the template
346
 
//  if (obj->TemplateInstance ())
347
 
//    obj = obj->TemplateInstance ()->Template ();
348
 
 
349
 
  // functions that are only friend declarations of an assigned scope
350
 
  CScopeInfo *assigned = obj->AssignedScope ();
351
 
  if (assigned)
352
 
    return (assigned->GlobalScope () || assigned->isAnonymous ()) ? 0:assigned;
353
 
 
354
 
  CRecord *crec = obj->ClassScope ();
355
 
  CScopeInfo *qual = obj->QualifiedScope ();
356
 
  CScopeInfo *scope = obj->Scope ();
357
 
  return crec ? (CScopeInfo*)crec : (qual ? qual :
358
 
    ((scope->GlobalScope () || scope->isAnonymous ()) ? 0 : scope));
359
 
}
360
 
 
361
 
void WeaverBase::rename_args (CFunctionInfo *func, const char * new_name, vector<string> &arg_names) {
362
 
  // first rename the arguments in the argument list
363
 
  for (unsigned arg = 0; arg < func->Arguments (); arg++) {
364
 
    if (func->Argument (arg)->isAnonymous()) {
365
 
      // create a new name
366
 
      ostringstream name;
367
 
      name << new_name << arg;
368
 
      // insert the generated name
369
 
      rename (func->Argument (arg), name.str ());
370
 
      arg_names.push_back (name.str ());
371
 
    }
372
 
    else {
373
 
      arg_names.push_back (func->Argument (arg)->Name ().c_str());
374
 
    }
375
 
  }
376
 
}
377
 
 
378
 
void WeaverBase::rename (CArgumentInfo *arg, const string &new_name) {
379
 
  // don't change anything with void arguments
380
 
  if (arg->TypeInfo ()->is_void ())
381
 
    return;
382
 
 
383
 
  // find the syntax tree node of the argument name
384
 
  CT_ArgDecl *arg_decl = (CT_ArgDecl*)arg->Tree ();
385
 
  CT_Declarator *declarator = (CT_Declarator*)arg_decl->Declarator ();
386
 
  CT_SimpleName *arg_name = name (declarator);
387
 
 
388
 
  if (arg_name->NodeName () != CT_PrivateName::NodeId ()) {
389
 
    replace (arg_name, new_name);
390
 
  }
391
 
  else {
392
 
    // in the case of an anonymous argument I have to find an insert pos
393
 
    CTree *left = 0, *right = 0;
394
 
    if (declarator) {
395
 
      if (declarator->NodeName () == CT_InitDeclarator::NodeId ())
396
 
        right = ((CT_InitDeclarator*)declarator)->Initializer ();
397
 
      else if (declarator->NodeName () == CT_BracedDeclarator::NodeId ())
398
 
        right = declarator->Son (declarator->Sons () - 1);
399
 
      else if (declarator->NodeName () == CT_ArrayDeclarator::NodeId ())
400
 
        right = declarator->Son (1);
401
 
      else if (declarator->NodeName () == CT_FctDeclarator::NodeId ())
402
 
        right = declarator->Son (1);
403
 
      else if (declarator->NodeName () == CT_RefDeclarator::NodeId ())
404
 
        left = declarator->Son (0);
405
 
      else if (declarator->NodeName () == CT_PtrDeclarator::NodeId ())
406
 
        left = declarator->Son (declarator->Sons () - 2);
407
 
      else if (declarator->NodeName () == CT_MembPtrDeclarator::NodeId ())
408
 
        left = declarator->Son (declarator->Sons () - 2);
409
 
      else if (declarator->NodeName () == CT_BitFieldDeclarator::NodeId ())
410
 
        right = declarator->Son (1);
411
 
      else {
412
 
        _err << sev_fatal << declarator->token ()->location ()
413
 
             << "unknown declarator type" << endMessage;
414
 
        return;
415
 
      }
416
 
    }
417
 
    if (!left && !right) {
418
 
      // no declarator + anonymous => there must be at least a decl spec seq!
419
 
      left = arg_decl->DeclSpecs ();
420
 
    }
421
 
    if (left) {
422
 
      const WeavePos &lp = weave_pos (left->end_token (), WeavePos::WP_AFTER);
423
 
      paste (lp, new_name);
424
 
      paste (lp, " ");
425
 
    }
426
 
    else if (right) {
427
 
      const WeavePos &rp = weave_pos (right->token (), WeavePos::WP_BEFORE);
428
 
      paste (rp, " ");
429
 
      paste (rp, new_name);
430
 
    }
431
 
    else
432
 
      _err << sev_fatal << declarator->token ()->location ()
433
 
           << "found no hook to replace ananymous arg name" << endMessage;
434
 
  }
435
 
}
436
 
 
437
 
CT_SimpleName *WeaverBase::is_name (CTree *node) {
438
 
  if (node->NodeName () == CT_QualName::NodeId () ||
439
 
      node->NodeName () == CT_SimpleName::NodeId () ||
440
 
      node->NodeName () == CT_OperatorName::NodeId () ||
441
 
      node->NodeName () == CT_ConversionName::NodeId () ||
442
 
      node->NodeName () == CT_RootQualName::NodeId () ||
443
 
      node->NodeName () == CT_PrivateName::NodeId ())
444
 
    return (CT_SimpleName*)node;
445
 
  else
446
 
    return (CT_SimpleName*)0;
447
 
}
448
 
 
449
 
CT_FctDeclarator *WeaverBase::fct_declarator (CT_Declarator *declarator) {
450
 
  do {
451
 
    CT_Declarator *next = (CT_Declarator*)declarator->Declarator ();
452
 
    if (declarator->NodeName () == CT_FctDeclarator::NodeId () &&
453
 
        is_name (next))
454
 
      return (CT_FctDeclarator*)declarator;
455
 
    declarator = next;
456
 
  } while (!is_name (declarator));
457
 
  return (CT_FctDeclarator*)0;
458
 
}
459
 
 
460
 
CT_SimpleName *WeaverBase::name (CT_Declarator *&declarator) {
461
 
  CTree *node = declarator;
462
 
  declarator  = (CT_Declarator*)0;
463
 
  while (!is_name (node)) {
464
 
    declarator = (CT_Declarator*)node;
465
 
    node = declarator->Declarator ();
466
 
  }
467
 
 
468
 
  return (CT_SimpleName*)node;
469
 
}
470
 
 
471
 
// return LinkageSpec node for extern "C" <decl> like declarations
472
 
CTree *WeaverBase::linkage_adjust (CT_Decl *decl) {
473
 
  CT_LinkageSpec *linkage = decl->Linkage ();
474
 
  return (!linkage || linkage->isList ()) ? decl : linkage;
475
 
}
 
219
int WeaverBase::primary_len() const {
 
220
  return _primary_end->location().line() - _primary_start->location().line() + 1;
 
221
}
 
222