001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.jet.checkers;
018
019 import com.google.common.collect.Maps;
020 import com.intellij.psi.PsiElement;
021 import com.intellij.psi.tree.IElementType;
022 import com.intellij.psi.tree.TokenSet;
023 import com.intellij.psi.util.PsiTreeUtil;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.jet.JetNodeTypes;
026 import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
027 import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory;
028 import org.jetbrains.jet.lang.diagnostics.Diagnostic;
029 import org.jetbrains.jet.lang.diagnostics.Errors;
030 import org.jetbrains.jet.lang.psi.*;
031 import org.jetbrains.jet.lang.resolve.BindingContext;
032 import org.jetbrains.jet.lang.resolve.BindingContextUtils;
033 import org.jetbrains.jet.lang.types.ErrorUtils;
034 import org.jetbrains.jet.lang.types.JetType;
035 import org.jetbrains.jet.lexer.JetTokens;
036
037 import java.util.Collection;
038 import java.util.Map;
039
040 import static org.jetbrains.jet.lang.resolve.BindingContext.*;
041 import static org.jetbrains.jet.lexer.JetTokens.*;
042
043 public class DebugInfoUtil {
044 private static final TokenSet EXCLUDED = TokenSet.create(
045 COLON, AS_KEYWORD, AS_SAFE, IS_KEYWORD, NOT_IS, OROR, ANDAND, EQ, EQEQEQ, EXCLEQEQEQ, ELVIS, EXCLEXCL, IN_KEYWORD, NOT_IN);
046
047 public interface DebugInfoReporter {
048
049 void reportElementWithErrorType(@NotNull JetReferenceExpression expression);
050
051 void reportMissingUnresolved(@NotNull JetReferenceExpression expression);
052
053 void reportUnresolvedWithTarget(@NotNull JetReferenceExpression expression, @NotNull String target);
054 }
055
056 public static void markDebugAnnotations(
057 @NotNull PsiElement root,
058 @NotNull final BindingContext bindingContext,
059 @NotNull final DebugInfoReporter debugInfoReporter
060 ) {
061 final Map<JetReferenceExpression, DiagnosticFactory> markedWithErrorElements = Maps.newHashMap();
062 for (Diagnostic diagnostic : bindingContext.getDiagnostics()) {
063 DiagnosticFactory factory = diagnostic.getFactory();
064 if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(diagnostic.getFactory())) {
065 markedWithErrorElements.put((JetReferenceExpression) diagnostic.getPsiElement(), factory);
066 }
067 else if (factory == Errors.SUPER_IS_NOT_AN_EXPRESSION
068 || factory == Errors.SUPER_NOT_AVAILABLE) {
069 JetSuperExpression superExpression = (JetSuperExpression) diagnostic.getPsiElement();
070 markedWithErrorElements.put(superExpression.getInstanceReference(), factory);
071 }
072 else if (factory == Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND) {
073 markedWithErrorElements.put((JetSimpleNameExpression) diagnostic.getPsiElement(), factory);
074 }
075 else if (factory == Errors.UNSUPPORTED) {
076 for (JetReferenceExpression reference : PsiTreeUtil.findChildrenOfType(diagnostic.getPsiElement(),
077 JetReferenceExpression.class)) {
078 markedWithErrorElements.put(reference, factory);
079 }
080 }
081 }
082
083 root.acceptChildren(new JetTreeVisitorVoid() {
084
085 @Override
086 public void visitReferenceExpression(@NotNull JetReferenceExpression expression) {
087 super.visitReferenceExpression(expression);
088 if (!BindingContextUtils.isExpressionWithValidReference(expression, bindingContext)){
089 return;
090 }
091 if (expression instanceof JetSimpleNameExpression) {
092 JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) expression;
093 IElementType elementType = expression.getNode().getElementType();
094 if (elementType == JetNodeTypes.OPERATION_REFERENCE) {
095 IElementType referencedNameElementType = nameExpression.getReferencedNameElementType();
096 if (EXCLUDED.contains(referencedNameElementType)) {
097 return;
098 }
099 }
100 if (elementType == JetNodeTypes.LABEL ||
101 nameExpression.getReferencedNameElementType() == JetTokens.THIS_KEYWORD) {
102 return;
103 }
104 }
105
106 String target = null;
107 DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, expression);
108 if (declarationDescriptor != null) {
109 target = declarationDescriptor.toString();
110 }
111 if (target == null) {
112 PsiElement labelTarget = bindingContext.get(LABEL_TARGET, expression);
113 if (labelTarget != null) {
114 target = labelTarget.getText();
115 }
116 }
117 if (target == null) {
118 Collection<? extends DeclarationDescriptor> declarationDescriptors =
119 bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, expression);
120 if (declarationDescriptors != null) {
121 target = "[" + declarationDescriptors.size() + " descriptors]";
122 }
123 }
124 if (target == null) {
125 Collection<? extends PsiElement> labelTargets = bindingContext.get(AMBIGUOUS_LABEL_TARGET, expression);
126 if (labelTargets != null) {
127 target = "[" + labelTargets.size() + " elements]";
128 }
129 }
130
131 boolean resolved = target != null;
132 boolean markedWithError = markedWithErrorElements.containsKey(expression);
133 if (expression instanceof JetArrayAccessExpression &&
134 markedWithErrorElements.containsKey(((JetArrayAccessExpression) expression).getArrayExpression())) {
135 // if 'foo' in 'foo[i]' is unresolved it means 'foo[i]' is unresolved (otherwise 'foo[i]' is marked as 'missing unresolved')
136 markedWithError = true;
137 }
138 JetType expressionType = bindingContext.get(EXPRESSION_TYPE, expression);
139 DiagnosticFactory factory = markedWithErrorElements.get(expression);
140 if (declarationDescriptor != null &&
141 (ErrorUtils.isError(declarationDescriptor) || ErrorUtils.containsErrorType(expressionType))) {
142 if (factory != Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND) {
143 debugInfoReporter.reportElementWithErrorType(expression);
144 }
145 }
146 if (resolved && markedWithError) {
147 if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(factory)) {
148 debugInfoReporter.reportUnresolvedWithTarget(expression, target);
149 }
150 }
151 else if (!resolved && !markedWithError) {
152 debugInfoReporter.reportMissingUnresolved(expression);
153 }
154 }
155 });
156 }
157
158 }