summaryrefslogtreecommitdiff
path: root/java/debugger/impl/src/com/intellij/debugger/impl/JavaEditorTextProviderImpl.java
blob: 11b077340eb739cb67e2490d407329f96fa392f3 (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
157
158
159
160
161
/*
 * Copyright 2000-2011 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.
 */
package com.intellij.debugger.impl;

import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.debugger.engine.evaluation.CodeFragmentKind;
import com.intellij.debugger.engine.evaluation.TextWithImports;
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nullable;

/**
 * @author Maxim.Medvedev
 */
public class JavaEditorTextProviderImpl implements EditorTextProvider {
  private static final Logger LOG = Logger.getInstance(JavaEditorTextProviderImpl.class);

  @Override
  public TextWithImports getEditorText(PsiElement elementAtCaret) {
    String result = null;
    PsiElement element = findExpression(elementAtCaret);
    if (element == null) return null;
    if (element instanceof PsiVariable) {
      result = qualifyEnumConstant(element, ((PsiVariable)element).getName());
    }
    else if (element instanceof PsiMethod) {
      result = ((PsiMethod)element).getName() + "()";
    }
    else if (element instanceof PsiReferenceExpression) {
      PsiReferenceExpression reference = (PsiReferenceExpression)element;
      result = qualifyEnumConstant(reference.resolve(), element.getText());
    }
    else {
      result = element.getText();
    }
    return result != null? new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, result) : null;
  }

  @Nullable
  private static PsiElement findExpression(PsiElement element) {
    PsiElement e = PsiTreeUtil.getParentOfType(element, PsiVariable.class, PsiExpression.class, PsiMethod.class);
    if (e instanceof PsiVariable) {
      // return e;
    }
    else if (e instanceof PsiMethod && element.getParent() != e) {
      e = null;
    }
    else if (e instanceof PsiReferenceExpression) {
      if (e.getParent() instanceof PsiCallExpression) {
        e = e.getParent();
      }
      else if (e.getParent() instanceof PsiReferenceExpression) {
        // <caret>System.out case should not return plain class name
        PsiElement resolve = ((PsiReferenceExpression)e).resolve();
        if (resolve instanceof PsiClass) {
          e = e.getParent();
        }
      }
    }
    if (e instanceof PsiNewExpression) {
      // skip new Runnable() { ... }
      if (((PsiNewExpression)e).getAnonymousClass() != null) return null;
    }
    return e;
  }

  @Nullable
  public Pair<PsiElement, TextRange> findExpression(PsiElement element, boolean allowMethodCalls) {
    PsiElement expression = null;
    PsiElement parent = element.getParent();
    if (parent instanceof PsiVariable) {
      expression = element;
    }
    else if (parent instanceof PsiReferenceExpression) {
      final PsiElement pparent = parent.getParent();
      if (pparent instanceof PsiCallExpression) {
        parent = pparent;
      }
      else if (pparent instanceof PsiReferenceExpression) {
        PsiElement resolve = ((PsiReferenceExpression)parent).resolve();
        if (resolve instanceof PsiClass) {
          parent = pparent;
        }
      }
      if (allowMethodCalls || !DebuggerUtils.hasSideEffects(parent)) {
        expression = parent;
      }
    }
    else if (parent instanceof PsiThisExpression) {
      expression = parent;
    }
    else if (parent instanceof PsiInstanceOfExpression || parent instanceof PsiBinaryExpression || parent instanceof PsiPolyadicExpression) {
      if (allowMethodCalls || !DebuggerUtils.hasSideEffects(parent)) {
        expression = parent;
      }
    }
    else if (allowMethodCalls) {
      PsiElement e = PsiTreeUtil.getParentOfType(element, PsiVariable.class, PsiExpression.class, PsiMethod.class);
      if (e instanceof PsiNewExpression) {
        if (((PsiNewExpression)e).getAnonymousClass() == null) {
          expression = e;
        }
      }
    }

    if (expression != null) {
      try {
        PsiElement context = element;
        if(parent instanceof PsiParameter) {
          try {
            context = ((PsiMethod)((PsiParameter)parent).getDeclarationScope()).getBody();
          }
          catch (Throwable ignored) {
          }
        }
        else {
          while(context != null  && !(context instanceof PsiStatement) && !(context instanceof PsiClass)) {
            context = context.getParent();
          }
        }
        TextRange textRange = expression.getTextRange();
        PsiElement psiExpression = JavaPsiFacade.getInstance(expression.getProject()).getElementFactory().createExpressionFromText(expression.getText(), context);
        return Pair.create(psiExpression, textRange);
      }
      catch (IncorrectOperationException e) {
        LOG.debug(e);
      }
    }
    return null;
  }

  @Nullable
  private static String qualifyEnumConstant(PsiElement resolved, @Nullable String def) {
    if (resolved instanceof PsiEnumConstant) {
      final PsiEnumConstant enumConstant = (PsiEnumConstant)resolved;
      final PsiClass enumClass = enumConstant.getContainingClass();
      if (enumClass != null) {
        return enumClass.getName() + "." + enumConstant.getName();
      }
    }
    return def;
  }
}