File: PointCutEvaluator.cc

package info (click to toggle)
aspectc%2B%2B 1.0pre4~svn.20090918-1
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 117,308 kB
  • ctags: 410,601
  • sloc: cpp: 1,883,007; ansic: 17,279; sh: 2,190; makefile: 1,088
file content (333 lines) | stat: -rw-r--r-- 11,705 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
// This file is part of the AspectC++ compiler 'ac++'.
// Copyright (C) 1999-2003  The 'ac++' developers (see aspectc.org)
//                                                                
// This program is free software;  you can redistribute it and/or 
// modify it under the terms of the GNU General Public License as 
// published by the Free Software Foundation; either version 2 of 
// the License, or (at your option) any later version.            
//                                                                
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
// GNU General Public License for more details.                   
//                                                                
// You should have received a copy of the GNU General Public      
// License along with this program; if not, write to the Free     
// Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
// MA  02111-1307  USA                                            

#include <set>
using namespace std;

#include "PointCutEvaluator.h"
#include "PointCutExpr.h"
#include "PointCutContext.h"
#include "Binding.h"
#include "Naming.h"

#include "Puma/ACClassDatabase.h"
#include "Puma/ACPointcutInfo.h"
#include "Puma/ACAspectInfo.h"
#include "Puma/ErrorSink.h"
#include "Puma/ErrorSeverity.h"
#include "Puma/CObjectInfo.h"
#include "Puma/CClassInfo.h"
#include "Puma/CFunctionInfo.h"
#include "Puma/CArgumentInfo.h"
#include "Puma/CTypeInfo.h"
#include "Puma/CTree.h"

void PointCutEvaluator::work (PointCut &pc, Binding &binding, CTree *pc_node,
#ifdef ACMODEL
			      JoinPointType expected) {
#else
            JoinPointLoc::join_point_type expected) {
#endif
  // create an abstract syntax tree of the expression
  PointCutExpr *expr = create (pc_node, expected);
  
  // do the evaluation
  work (pc, binding, expr, expected);

  // destroy the syntax tree
  destroy (expr);
}

void PointCutEvaluator::work (PointCut &pc, Binding &binding,
#ifdef ACMODEL
    PointCutExpr *expr, JoinPointType expected) {
#else
    PointCutExpr *expr, JoinPointLoc::join_point_type expected) {
#endif    
  // if there was an error, return immediately
  if (!expr)
    return;
  
  // if there was no error, check each join point if it belong to the pointcut

  // filter the joinpoints: only expected joinpoints are considered
#ifdef ACMODEL
  ProjectModel::Selection all;
#else
  JoinPointModel::Selection all;
#endif
  _context.jpm ().select (expected, all);
    
  bool have_binding = false;
#ifdef ACMODEL
  for (ProjectModel::Selection::iterator iter = all.begin ();
#else
  for (JoinPointModel::Selection::iterator iter = all.begin ();
#endif
  iter != all.end (); ++iter) {
#ifdef ACMODEL
    ACM_Any &jpl = (ACM_Any&)**iter;
#else
    JoinPointLoc &jpl = **iter;
#endif
    Binding this_binding;
    Condition condition;
    _context.pseudo_true (false);
    if (expr->evaluate (jpl, _context, this_binding, condition)) {
      pc.append (*new JoinPoint (&jpl, condition));
#ifdef ACMODEL
      if (jpl.type_val () == JPT_Call && !jpl.get_parent()) // TODO: pseud
#else
      if (jpl.type () == JoinPointLoc::MethodCall &&
          ((JPL_MethodCall&)jpl).is_pseudo ())
#endif
        continue;
      // check if the context variable binding is the same for all non-pseudo
      // join points
      if (!have_binding) {
        binding = this_binding;
        have_binding = true;
      }
      else if (binding != this_binding) {
        _err << sev_error;
        if (expr->node () && expr->node ()->token ()) 
          _err << expr->node ()->token ()->location ();
        _err << "incompatible argument bindings in pointcut expression" 
             << endMessage;
        return;
      }
    }
  }
  
  // copy the cflow trigger pointcut from the expressions to the pointcut
  for (set<PointCutExpr*>::const_iterator iter = _context.cflows ().begin ();
       iter != _context.cflows ().end (); ++iter) {
    pc.cflow_triggers(((PCE_CFlow*)*iter)->arg_pointcut ());
  }
  _context.cflow_reset ();
  
  // finally set the pointcut type before destroy the expression(!)
  pc.type (expr->type() == PCE_CODE ? PointCut::PCT_CODE : PointCut::PCT_CLASS);
  
//  cout << "PC:" << endl << pc;
}


PointCutExpr *PointCutEvaluator::create (CTree *pc_node,
#ifdef ACMODEL
    JoinPointType expected) {
#else
    JoinPointLoc::join_point_type expected) {
#endif
  // transform the parser syntax tree into a real pointcat expression
  PointCutExpr *expr = create_tree (pc_node);
  if (_context.func ())
    expr = new PCE_Named (_context.func (), expr);
  
  // do a semantic analysis / error checking
  assert (expected & (JoinPointLoc::Name | JoinPointLoc::Code));
  expr->semantics (_err, _context);

  // check if the whole expression has the expected type
#ifdef ACMODEL
  bool names_allowed = (expected & JPT_Name);
  bool code_allowed  = (expected & JPT_Code);
#else
  bool names_allowed = (expected & JoinPointLoc::Name);
  bool code_allowed  = (expected & JoinPointLoc::Code);
#endif
  if ((expr->type() == PCE_NAME && !names_allowed) ||
      (expr->type() == PCE_CODE && !code_allowed)) {
    _err << sev_error << pc_node->token ()->location ()
         << "unexpected pointcut type '"
         << (expr->type() == PCE_CODE ? "code" : "name") << "'" << endMessage;
  }

  if (_err.severity () >= sev_error) {
    // destroy the syntax tree
    destroy (expr);
    expr = 0;
  }
  
  return expr;
}


void PointCutEvaluator::destroy (PointCutExpr * expr) {
  if (!expr) return;
  for (int i = 0; i < expr->args (); i++)
    destroy (expr->arg (i));
  delete expr;
}

PointCutExpr *PointCutEvaluator::create_tree (CTree *node) {
  PointCutExpr *result = (PointCutExpr*)0;;

  // skip braces and builtin cast nodes
  while (true) {
    if (node->NodeName () == CT_ImplicitCast::NodeId ())
      node = ((CT_ImplicitCast*)node)->Expr ();
    else if (node->NodeName () == CT_BracedExpr::NodeId ())
      node = ((CT_BracedExpr*)node)->Expr ();
    else
      break;
  }

  // now handle builtin pointcut functions and named pointcuts
  if (node->NodeName () == CT_CallExpr::NodeId ()) {

    CT_CallExpr *call_node = (CT_CallExpr*)node;
    CT_ExprList *args = call_node->Arguments ();
    CFunctionInfo *func = call_node->Object ()->FunctionInfo ();

    if (!func) {
      _err << sev_error << node->token ()->location ()
	   << "invalid pointcut" << endMessage;
      return (PointCutExpr*)0;
    }
    
    const char *name = func->Name ();
    // check for built-in operators
    if (func->isBuiltin ()) {
      if (strcmp (name, "operator &&") == 0) {
        CT_BinaryExpr *expr = (CT_BinaryExpr*)node->Son (0);
        result = new PCE_And (create_tree (expr->Son (0)), create_tree (expr->Son(2)));
      }
      else if (strcmp (name, "operator ||") == 0) {
        CT_BinaryExpr *expr = (CT_BinaryExpr*)node->Son (0);
        result = new PCE_Or (create_tree (expr->Son (0)), create_tree (expr->Son(2)));
      }
      else if (strcmp (name, "operator !") == 0) {
        CT_UnaryExpr *expr = (CT_UnaryExpr*)node->Son (0);
        result = new PCE_Not (create_tree (expr->Son (1)));
      }
      else {
        _err << sev_error << node->token ()->location ()
             << "invalid built-in operator in pointcut" << endMessage;
        return (PointCutExpr*)0;
      }
    }
    // check for builtin pointcut functions
    else if (func->Scope ()->ScopeInfo()->GlobalScope()) {
      bool check_arg_count = true;
      if (strcmp (name, "classes") == 0)
        result = new PCE_Classes (create_tree (args->Entry (0)));
      else if (strcmp (name, "base") == 0)
        result = new PCE_Base (create_tree (args->Entry (0)));
      else if (strcmp (name, "derived") == 0)
        result = new PCE_Derived (create_tree (args->Entry (0)));
      else if (strcmp (name, "within") == 0)
        result = new PCE_Within (create_tree (args->Entry (0)));
      else if (strcmp (name, "execution") == 0)
        result = new PCE_Execution (create_tree (args->Entry (0)));
      else if (strcmp (name, "call") == 0)
        result = new PCE_Call (create_tree (args->Entry (0)));
      else if (strcmp (name, "construction") == 0)
        result = new PCE_Construction (create_tree (args->Entry (0)));
      else if (strcmp (name, "destruction") == 0)
        result = new PCE_Destruction (create_tree (args->Entry (0)));
      else if (strcmp (name, "that") == 0)
        result = new PCE_That (create_tree (args->Entry (0)));
      else if (strcmp (name, "target") == 0)
        result = new PCE_Target (create_tree (args->Entry (0)));
      else if (strcmp (name, "cflow") == 0)
        result = new PCE_CFlow (create_tree (args->Entry (0)));
      else if (strcmp (name, "args") == 0) {
        PCE_Args *args_node = new PCE_Args;
        for (int i = 0; i < args->Entries (); i++)
          args_node->add_arg (create_tree (args->Entry (i)));
        result = args_node;
        check_arg_count = false;
      }
      else if (strcmp (name, "result") == 0)
        result = new PCE_Result (create_tree (args->Entry (0)));
      else {
        result = (PointCutExpr*)0; // no builtin pointcut function!
        check_arg_count = false;
      }

      if (check_arg_count && args->Entries () > 1) {
        _err << sev_error << node->token ()->location ()
             << "pointcut function '" << name << "' has only one argument" 
             << endMessage;
        return (PointCutExpr*)0;
      }
    }

    // handle user-defined (named) pointcuts
    if (!result) {

      // look up the real pointcut function (might be virtual!)
      if (!(func = _context.lookup_pointcut (func, _err, node)))
	return (PointCutExpr*)0;

      // create a node
      CFunctionInfo *save = _context.func (func); // needed?
      result = new PCE_Named (func, create_tree (func->Init ()->Entry (0)));
      _context.func (save);
    }
  }
  else if (node->NodeName () == CT_BinaryExpr::NodeId ()) {
    // check for binary operators
    CT_BinaryExpr *expr = (CT_BinaryExpr*)node;
    const char *oper = expr->Son (1)->token ()->text ();
    
    if (strcmp (oper, "&&") == 0)
      result = new PCE_And (create_tree (expr->Son (0)), create_tree (expr->Son(2)));
    else if (strcmp (oper, "||") == 0)
      result = new PCE_Or (create_tree (expr->Son (0)), create_tree (expr->Son(2)));
    else {
      _err << sev_error << node->token ()->location ()
     << "invalid binary expression in pointcut" << endMessage;
      return (PointCutExpr*)0;
    }
  }
  else if (node->NodeName () == CT_UnaryExpr::NodeId ()) {
    // check for unary operators
    CT_UnaryExpr *expr = (CT_UnaryExpr*)node;
    const char *oper = expr->Son (0)->token ()->text ();
    
    if (strcmp (oper, "!") == 0)
      result = new PCE_Not (create_tree (expr->Son(1)));
    else {
      _err << sev_error << node->token ()->location ()
     << "invalid unary expression in pointcut" << endMessage;
      return (PointCutExpr*)0;
    }
  }
  else if (node->NodeName () == CT_String::NodeId ()) {
    // this match be a match string
    result = new PCE_Match (((CT_String*)node)->Value ()->StrLiteral ()->
			    String ());
  }
  else if (node->NodeName () == CT_SimpleName::NodeId ()) {
    // this must be the name of a context variable
    result = new PCE_ContextVar (((CT_SimpleName*)node)->Object ()->Name ());
  }
  else {
    // hm, unknown node type -> must be an invalid expression
    _err << sev_error << node->token ()->location ()
	 << "invalid pointcut expression" << endMessage;
    return (PointCutExpr*)0;
  }

  result->node (node);

  return result;
}