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 org.jetbrains.annotations.NotNull;
024 import org.jetbrains.jet.JetNodeTypes;
025 import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
026 import org.jetbrains.jet.lang.diagnostics.AbstractDiagnosticFactory;
027 import org.jetbrains.jet.lang.diagnostics.Diagnostic;
028 import org.jetbrains.jet.lang.diagnostics.Errors;
029 import org.jetbrains.jet.lang.psi.JetReferenceExpression;
030 import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
031 import org.jetbrains.jet.lang.psi.JetSuperExpression;
032 import org.jetbrains.jet.lang.psi.JetTreeVisitorVoid;
033 import org.jetbrains.jet.lang.resolve.BindingContext;
034 import org.jetbrains.jet.lang.resolve.BindingContextUtils;
035 import org.jetbrains.jet.lang.types.ErrorUtils;
036 import org.jetbrains.jet.lang.types.JetType;
037 import org.jetbrains.jet.lexer.JetTokens;
038
039 import java.util.Collection;
040 import java.util.Map;
041
042 import static org.jetbrains.jet.lang.resolve.BindingContext.*;
043 import static org.jetbrains.jet.lexer.JetTokens.*;
044
045 public class DebugInfoUtil {
046 private static final TokenSet EXCLUDED = TokenSet.create(
047 COLON, AS_KEYWORD, AS_SAFE, IS_KEYWORD, NOT_IS, OROR, ANDAND, EQ, EQEQEQ, EXCLEQEQEQ, ELVIS, EXCLEXCL, IN_KEYWORD, NOT_IN);
048
049 public interface DebugInfoReporter {
050
051 void reportElementWithErrorType(@NotNull JetReferenceExpression expression);
052
053 void reportMissingUnresolved(@NotNull JetReferenceExpression expression);
054
055 void reportUnresolvedWithTarget(@NotNull JetReferenceExpression expression, @NotNull String target);
056 }
057
058 public static void markDebugAnnotations(
059 @NotNull PsiElement root,
060 @NotNull final BindingContext bindingContext,
061 @NotNull final DebugInfoReporter debugInfoReporter
062 ) {
063 final Map<JetReferenceExpression, AbstractDiagnosticFactory> markedWithErrorElements = Maps.newHashMap();
064 for (Diagnostic diagnostic : bindingContext.getDiagnostics()) {
065 AbstractDiagnosticFactory factory = diagnostic.getFactory();
066 if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(diagnostic.getFactory())) {
067 markedWithErrorElements.put((JetReferenceExpression) diagnostic.getPsiElement(), factory);
068 }
069 else if (factory == Errors.SUPER_IS_NOT_AN_EXPRESSION
070 || factory == Errors.SUPER_NOT_AVAILABLE) {
071 JetSuperExpression superExpression = (JetSuperExpression) diagnostic.getPsiElement();
072 markedWithErrorElements.put(superExpression.getInstanceReference(), factory);
073 }
074 else if (factory == Errors.EXPRESSION_EXPECTED_NAMESPACE_FOUND) {
075 markedWithErrorElements.put((JetSimpleNameExpression) diagnostic.getPsiElement(), factory);
076 }
077 }
078
079 root.acceptChildren(new JetTreeVisitorVoid() {
080
081 @Override
082 public void visitReferenceExpression(JetReferenceExpression expression) {
083 super.visitReferenceExpression(expression);
084 if (!BindingContextUtils.isExpressionWithValidReference(expression, bindingContext)){
085 return;
086 }
087 if (expression instanceof JetSimpleNameExpression) {
088 JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) expression;
089 IElementType elementType = expression.getNode().getElementType();
090 if (elementType == JetNodeTypes.OPERATION_REFERENCE) {
091 IElementType referencedNameElementType = nameExpression.getReferencedNameElementType();
092 if (EXCLUDED.contains(referencedNameElementType)) {
093 return;
094 }
095 if (JetTokens.LABELS.contains(referencedNameElementType)) return;
096 }
097 else if (nameExpression.getReferencedNameElementType() == JetTokens.THIS_KEYWORD) {
098 return;
099 }
100 }
101
102 String target = null;
103 DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, expression);
104 if (declarationDescriptor != null) {
105 target = declarationDescriptor.toString();
106 }
107 if (target == null) {
108 PsiElement labelTarget = bindingContext.get(LABEL_TARGET, expression);
109 if (labelTarget != null) {
110 target = labelTarget.getText();
111 }
112 }
113 if (target == null) {
114 Collection<? extends DeclarationDescriptor> declarationDescriptors =
115 bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, expression);
116 if (declarationDescriptors != null) {
117 target = "[" + declarationDescriptors.size() + " descriptors]";
118 }
119 }
120 if (target == null) {
121 Collection<? extends PsiElement> labelTargets = bindingContext.get(AMBIGUOUS_LABEL_TARGET, expression);
122 if (labelTargets != null) {
123 target = "[" + labelTargets.size() + " elements]";
124 }
125 }
126
127 boolean resolved = target != null;
128 boolean markedWithError = markedWithErrorElements.containsKey(expression);
129 JetType expressionType = bindingContext.get(EXPRESSION_TYPE, expression);
130 AbstractDiagnosticFactory factory = markedWithErrorElements.get(expression);
131 if (declarationDescriptor != null &&
132 (ErrorUtils.isError(declarationDescriptor) || ErrorUtils.containsErrorType(expressionType))) {
133 if (factory != Errors.EXPRESSION_EXPECTED_NAMESPACE_FOUND) {
134 debugInfoReporter.reportElementWithErrorType(expression);
135 }
136 }
137 if (resolved && markedWithError) {
138 if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(factory)) {
139 debugInfoReporter.reportUnresolvedWithTarget(expression, target);
140 }
141 }
142 else if (!resolved && !markedWithError) {
143 debugInfoReporter.reportMissingUnresolved(expression);
144 }
145 }
146 });
147 }
148
149 }