summaryrefslogtreecommitdiff
path: root/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java
blob: d299af17234007aa863d93163d5ddb07fdfbd974 (plain)
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
/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Class MethodEvaluator
 * @author Jeka
 */
package com.intellij.debugger.engine.evaluation.expression;

import com.intellij.debugger.DebuggerBundle;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.debugger.engine.JVMName;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
import com.intellij.debugger.engine.evaluation.EvaluateRuntimeException;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.openapi.diagnostic.Logger;
import com.sun.jdi.*;

import java.util.ArrayList;
import java.util.List;

public class MethodEvaluator implements Evaluator {
  private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.evaluation.expression.MethodEvaluator");
  private final JVMName myClassName;
  private final JVMName myMethodSignature;
  private final String myMethodName;
  private final Evaluator[] myArgumentEvaluators;
  private final Evaluator myObjectEvaluator;

  public MethodEvaluator(Evaluator objectEvaluator, JVMName className, String methodName, JVMName signature, Evaluator[] argumentEvaluators) {
    myObjectEvaluator = new DisableGC(objectEvaluator);
    myClassName = className;
    myMethodName = methodName;
    myMethodSignature = signature;
    myArgumentEvaluators = argumentEvaluators;
  }

  @Override
  public Modifier getModifier() {
    return null;
  }

  @Override
  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
    if(!context.getDebugProcess().isAttached()) return null;
    DebugProcessImpl debugProcess = context.getDebugProcess();
    
    final boolean requiresSuperObject = 
      myObjectEvaluator instanceof SuperEvaluator || 
      (myObjectEvaluator instanceof DisableGC && ((DisableGC)myObjectEvaluator).getDelegate() instanceof SuperEvaluator);
    
    final Object object = myObjectEvaluator.evaluate(context);
    if (LOG.isDebugEnabled()) {
      LOG.debug("MethodEvaluator: object = " + object);
    }
    if(object == null) {
      throw EvaluateExceptionUtil.createEvaluateException(new NullPointerException());
    }
    if (!(object instanceof ObjectReference || object instanceof ClassType)) {
      throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.evaluating.method", myMethodName));
    }
    List args = new ArrayList(myArgumentEvaluators.length);
    for (Evaluator evaluator : myArgumentEvaluators) {
      args.add(evaluator.evaluate(context));
    }
    try {
      ReferenceType referenceType = null;

      if(object instanceof ObjectReference) {
        final ReferenceType qualifierType = ((ObjectReference)object).referenceType();
        referenceType = debugProcess.findClass(context, qualifierType.name(), qualifierType.classLoader());
      }
      else if(object instanceof ClassType) {
        final ClassType qualifierType = (ClassType)object;
        referenceType = debugProcess.findClass(context, qualifierType.name(), context.getClassLoader());
      }
      else {
        final String className = myClassName != null? myClassName.getName(debugProcess) : null;
        if (className != null) {
          referenceType = debugProcess.findClass(context, className, context.getClassLoader());
        }
      }
      
      if (referenceType == null) {
        throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(
          DebuggerBundle.message("evaluation.error.cannot.evaluate.qualifier", myMethodName))
        );
      }
      final String signature = myMethodSignature != null ? myMethodSignature.getName(debugProcess) : null;
      final String methodName = DebuggerUtilsEx.methodName(referenceType.name(), myMethodName, signature);
      if (object instanceof ClassType) {
        if(referenceType instanceof ClassType) {
          Method jdiMethod;
          if(myMethodSignature != null) {
            jdiMethod = ((ClassType)referenceType).concreteMethodByName(myMethodName, myMethodSignature.getName(debugProcess));
          }
          else {
            List list = referenceType.methodsByName(myMethodName);
            jdiMethod = (Method)(list.size() > 0 ? list.get(0) : null);
          }
          if (jdiMethod != null && jdiMethod.isStatic()) {
            return debugProcess.invokeMethod(context, (ClassType)referenceType, jdiMethod, args);
          }
        }
        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.no.static.method", methodName));
      }
      // object should be an ObjectReference
      final ObjectReference objRef = (ObjectReference)object;
      ReferenceType _refType = referenceType;
      if (requiresSuperObject && (referenceType instanceof ClassType)) {
        _refType = ((ClassType)referenceType).superclass();
      }
      Method jdiMethod = DebuggerUtils.findMethod(_refType, myMethodName, signature);
      if (jdiMethod == null || jdiMethod.argumentTypes().size() != args.size()) {
        // dummy matching, may be improved with types matching later
        List<Method> methods = _refType.methodsByName(myMethodName);
        for (Method method : methods) {
          List<Type> types = method.argumentTypes();
          if (types.size() == args.size()) {
            jdiMethod = method;
            break;
          }
        }
      }
      if (jdiMethod == null) {
        throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.no.instance.method", methodName));
      }
      if (requiresSuperObject) {
        return debugProcess.invokeInstanceMethod(context, objRef, jdiMethod, args, ObjectReference.INVOKE_NONVIRTUAL);
      }
      return debugProcess.invokeMethod(context, objRef, jdiMethod, args);
    }
    catch (Exception e) {
      if (LOG.isDebugEnabled()) {
        LOG.debug(e);
      }
      throw EvaluateExceptionUtil.createEvaluateException(e);
    }
  }
}