Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.checkers.DebugInfoUtil Maven / Gradle / Ivy
/*
* Copyright 2010-2015 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 org.jetbrains.kotlin.checkers;
import com.google.common.collect.Maps;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.KtNodeTypes;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
import org.jetbrains.kotlin.descriptors.VariableDescriptor;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt;
import org.jetbrains.kotlin.types.ErrorUtils;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
import java.util.Collection;
import java.util.Map;
import static org.jetbrains.kotlin.lexer.KtTokens.*;
import static org.jetbrains.kotlin.resolve.BindingContext.*;
public class DebugInfoUtil {
private static final TokenSet MAY_BE_UNRESOLVED = TokenSet.create(IN_KEYWORD, NOT_IN);
private static final TokenSet EXCLUDED = TokenSet.create(
COLON, AS_KEYWORD, AS_SAFE, IS_KEYWORD, NOT_IS, OROR, ANDAND, EQ, EQEQEQ, EXCLEQEQEQ, ELVIS, EXCLEXCL);
public abstract static class DebugInfoReporter {
public void preProcessReference(@NotNull KtReferenceExpression expression) {
// do nothing
}
public abstract void reportElementWithErrorType(@NotNull KtReferenceExpression expression);
public abstract void reportMissingUnresolved(@NotNull KtReferenceExpression expression);
public abstract void reportUnresolvedWithTarget(@NotNull KtReferenceExpression expression, @NotNull String target);
public void reportDynamicCall(@NotNull KtElement element, DeclarationDescriptor declarationDescriptor) { }
}
public static void markDebugAnnotations(
@NotNull PsiElement root,
@NotNull final BindingContext bindingContext,
@NotNull final DebugInfoReporter debugInfoReporter
) {
final Map> markedWithErrorElements = Maps.newHashMap();
for (Diagnostic diagnostic : bindingContext.getDiagnostics()) {
DiagnosticFactory> factory = diagnostic.getFactory();
if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(diagnostic.getFactory())) {
markedWithErrorElements.put((KtReferenceExpression) diagnostic.getPsiElement(), factory);
}
else if (factory == Errors.SUPER_IS_NOT_AN_EXPRESSION
|| factory == Errors.SUPER_NOT_AVAILABLE) {
KtSuperExpression superExpression = (KtSuperExpression) diagnostic.getPsiElement();
markedWithErrorElements.put(superExpression.getInstanceReference(), factory);
}
else if (factory == Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND) {
markedWithErrorElements.put((KtSimpleNameExpression) diagnostic.getPsiElement(), factory);
}
else if (factory == Errors.UNSUPPORTED) {
for (KtReferenceExpression reference : PsiTreeUtil.findChildrenOfType(diagnostic.getPsiElement(),
KtReferenceExpression.class)) {
markedWithErrorElements.put(reference, factory);
}
}
}
root.acceptChildren(new KtTreeVisitorVoid() {
@Override
public void visitForExpression(@NotNull KtForExpression expression) {
KtExpression range = expression.getLoopRange();
reportIfDynamicCall(range, range, LOOP_RANGE_ITERATOR_RESOLVED_CALL);
reportIfDynamicCall(range, range, LOOP_RANGE_HAS_NEXT_RESOLVED_CALL);
reportIfDynamicCall(range, range, LOOP_RANGE_NEXT_RESOLVED_CALL);
super.visitForExpression(expression);
}
@Override
public void visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration destructuringDeclaration) {
for (KtDestructuringDeclarationEntry entry : destructuringDeclaration.getEntries()) {
reportIfDynamicCall(entry, entry, COMPONENT_RESOLVED_CALL);
}
super.visitDestructuringDeclaration(destructuringDeclaration);
}
@Override
public void visitProperty(@NotNull KtProperty property) {
VariableDescriptor descriptor = bindingContext.get(VARIABLE, property);
if (descriptor instanceof PropertyDescriptor && property.getDelegate() != null) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
reportIfDynamicCall(property.getDelegate(), propertyDescriptor.getGetter(), DELEGATED_PROPERTY_RESOLVED_CALL);
reportIfDynamicCall(property.getDelegate(), propertyDescriptor.getSetter(), DELEGATED_PROPERTY_RESOLVED_CALL);
reportIfDynamicCall(property.getDelegate(), propertyDescriptor, DELEGATED_PROPERTY_PD_RESOLVED_CALL);
}
super.visitProperty(property);
}
@Override
public void visitThisExpression(@NotNull KtThisExpression expression) {
ResolvedCall extends CallableDescriptor> resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext);
if (resolvedCall != null) {
reportIfDynamic(expression, resolvedCall.getResultingDescriptor(), debugInfoReporter);
}
super.visitThisExpression(expression);
}
@Override
public void visitReferenceExpression(@NotNull KtReferenceExpression expression) {
super.visitReferenceExpression(expression);
if (!BindingContextUtils.isExpressionWithValidReference(expression, bindingContext)){
return;
}
IElementType referencedNameElementType = null;
if (expression instanceof KtSimpleNameExpression) {
KtSimpleNameExpression nameExpression = (KtSimpleNameExpression) expression;
IElementType elementType = expression.getNode().getElementType();
if (elementType == KtNodeTypes.OPERATION_REFERENCE) {
referencedNameElementType = nameExpression.getReferencedNameElementType();
if (EXCLUDED.contains(referencedNameElementType)) {
return;
}
}
if (elementType == KtNodeTypes.LABEL ||
nameExpression.getReferencedNameElementType() == KtTokens.THIS_KEYWORD) {
return;
}
}
debugInfoReporter.preProcessReference(expression);
String target = null;
DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, expression);
if (declarationDescriptor != null) {
target = declarationDescriptor.toString();
reportIfDynamic(expression, declarationDescriptor, debugInfoReporter);
}
if (target == null) {
PsiElement labelTarget = bindingContext.get(LABEL_TARGET, expression);
if (labelTarget != null) {
target = labelTarget.getText();
}
}
if (target == null) {
Collection extends DeclarationDescriptor> declarationDescriptors =
bindingContext.get(AMBIGUOUS_REFERENCE_TARGET, expression);
if (declarationDescriptors != null) {
target = "[" + declarationDescriptors.size() + " descriptors]";
}
}
if (target == null) {
Collection extends PsiElement> labelTargets = bindingContext.get(AMBIGUOUS_LABEL_TARGET, expression);
if (labelTargets != null) {
target = "[" + labelTargets.size() + " elements]";
}
}
if (MAY_BE_UNRESOLVED.contains(referencedNameElementType)) {
return;
}
boolean resolved = target != null;
boolean markedWithError = markedWithErrorElements.containsKey(expression);
if (expression instanceof KtArrayAccessExpression &&
markedWithErrorElements.containsKey(((KtArrayAccessExpression) expression).getArrayExpression())) {
// if 'foo' in 'foo[i]' is unresolved it means 'foo[i]' is unresolved (otherwise 'foo[i]' is marked as 'missing unresolved')
markedWithError = true;
}
KotlinType expressionType = bindingContext.getType(expression);
DiagnosticFactory> factory = markedWithErrorElements.get(expression);
if (declarationDescriptor != null &&
(ErrorUtils.isError(declarationDescriptor) || ErrorUtils.containsErrorType(expressionType))) {
if (factory != Errors.EXPRESSION_EXPECTED_PACKAGE_FOUND) {
debugInfoReporter.reportElementWithErrorType(expression);
}
}
if (resolved && markedWithError) {
if (Errors.UNRESOLVED_REFERENCE_DIAGNOSTICS.contains(factory)) {
debugInfoReporter.reportUnresolvedWithTarget(expression, target);
}
}
else if (!resolved && !markedWithError) {
debugInfoReporter.reportMissingUnresolved(expression);
}
}
private boolean reportIfDynamicCall(E element, K key, WritableSlice> slice) {
ResolvedCall resolvedCall = bindingContext.get(slice, key);
if (resolvedCall != null) {
return reportIfDynamic(element, resolvedCall.getResultingDescriptor(), debugInfoReporter);
}
return false;
}
});
}
private static boolean reportIfDynamic(KtElement element, DeclarationDescriptor declarationDescriptor, DebugInfoReporter debugInfoReporter) {
if (declarationDescriptor != null && DynamicCallsKt.isDynamic(declarationDescriptor)) {
debugInfoReporter.reportDynamicCall(element, declarationDescriptor);
return true;
}
return false;
}
}