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 if (JetTokens.LABELS.contains(referencedNameElementType)) return; 100 } 101 else if (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 JetType expressionType = bindingContext.get(EXPRESSION_TYPE, expression); 134 DiagnosticFactory factory = markedWithErrorElements.get(expression); 135 if (declarationDescriptor != null && 136 (ErrorUtils.isError(declarationDescriptor) || ErrorUtils.containsErrorType(expressionType))) { 137 if (factory != Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND) { 138 debugInfoReporter.reportElementWithErrorType(expression); 139 } 140 } 141 if (resolved && markedWithError) { 142 if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(factory)) { 143 debugInfoReporter.reportUnresolvedWithTarget(expression, target); 144 } 145 } 146 else if (!resolved && !markedWithError) { 147 debugInfoReporter.reportMissingUnresolved(expression); 148 } 149 } 150 }); 151 } 152 153 }