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 017package org.jetbrains.jet.checkers; 018 019import com.google.common.collect.Maps; 020import com.intellij.psi.PsiElement; 021import com.intellij.psi.tree.IElementType; 022import com.intellij.psi.tree.TokenSet; 023import org.jetbrains.annotations.NotNull; 024import org.jetbrains.jet.JetNodeTypes; 025import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; 026import org.jetbrains.jet.lang.diagnostics.AbstractDiagnosticFactory; 027import org.jetbrains.jet.lang.diagnostics.Diagnostic; 028import org.jetbrains.jet.lang.diagnostics.Errors; 029import org.jetbrains.jet.lang.psi.JetReferenceExpression; 030import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; 031import org.jetbrains.jet.lang.psi.JetSuperExpression; 032import org.jetbrains.jet.lang.psi.JetTreeVisitorVoid; 033import org.jetbrains.jet.lang.resolve.BindingContext; 034import org.jetbrains.jet.lang.resolve.BindingContextUtils; 035import org.jetbrains.jet.lang.types.ErrorUtils; 036import org.jetbrains.jet.lang.types.JetType; 037import org.jetbrains.jet.lexer.JetTokens; 038 039import java.util.Collection; 040import java.util.Map; 041 042import static org.jetbrains.jet.lang.resolve.BindingContext.*; 043import static org.jetbrains.jet.lexer.JetTokens.*; 044 045public 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}