/* * Copyright 2013-2017 consulo.io * * 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 consulo.csharp.ide.highlight.check.impl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import consulo.csharp.ide.CSharpErrorBundle; import consulo.csharp.ide.highlight.CSharpHighlightContext; import consulo.csharp.ide.highlight.CSharpHighlightKey; import consulo.csharp.ide.highlight.check.CompilerCheck; import consulo.csharp.ide.highlight.quickFix.ReplaceTypeQuickFix; import consulo.csharp.lang.psi.CSharpElementVisitor; import consulo.csharp.lang.psi.CSharpLocalVariable; import consulo.csharp.lang.psi.impl.CSharpTypeUtil; import consulo.csharp.lang.psi.impl.source.CSharpForeachStatementImpl; import consulo.csharp.lang.psi.impl.source.CSharpTypeCastExpressionImpl; import consulo.csharp.lang.psi.impl.source.resolve.util.CSharpResolveUtil; import consulo.csharp.module.extension.CSharpLanguageVersion; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; import consulo.annotations.RequiredReadAction; import consulo.csharp.lang.CSharpCastType; import consulo.dotnet.psi.DotNetExpression; import consulo.dotnet.psi.DotNetType; import consulo.dotnet.resolve.DotNetTypeRef; import consulo.ide.eap.EarlyAccessProgramDescriptor; import consulo.ide.eap.EarlyAccessProgramManager; /** * @author VISTALL * @since 14.12.14 */ public class CS0030 extends CompilerCheck<PsiElement> { public static class CS0030TypeCast extends EarlyAccessProgramDescriptor { @NotNull @Override public String getName() { return "CS0030 Type cast checks"; } @NotNull @Override public String getDescription() { return ""; } } @RequiredReadAction @Nullable @Override public CompilerCheckBuilder checkImpl(@NotNull final CSharpLanguageVersion languageVersion, @NotNull CSharpHighlightContext highlightContext, @NotNull PsiElement element) { final Ref<CompilerCheckBuilder> ref = new Ref<CompilerCheckBuilder>(); element.accept(new CSharpElementVisitor() { @Override @RequiredReadAction public void visitForeachStatement(CSharpForeachStatementImpl statement) { CSharpLocalVariable variable = statement.getVariable(); if(variable == null) { return; } DotNetType type = variable.getType(); if(type == null) { return; } DotNetTypeRef variableTypeRef = type.toTypeRef(); if(variableTypeRef == DotNetTypeRef.AUTO_TYPE || variableTypeRef == DotNetTypeRef.ERROR_TYPE) { return; } DotNetTypeRef iterableTypeRef = CSharpResolveUtil.resolveIterableType(statement); if(iterableTypeRef == DotNetTypeRef.ERROR_TYPE) { return; } boolean success = CSharpTypeUtil.isInheritable(iterableTypeRef, variableTypeRef, statement) || CSharpTypeUtil.isInheritable(variableTypeRef, iterableTypeRef, statement); if(!success) { CompilerCheckBuilder builder = newBuilder(type, formatTypeRef(iterableTypeRef, statement), formatTypeRef(variableTypeRef, statement)); if(languageVersion.isAtLeast(CSharpLanguageVersion._3_0)) { builder.addQuickFix(new ReplaceTypeQuickFix(type, DotNetTypeRef.AUTO_TYPE)); } builder.addQuickFix(new ReplaceTypeQuickFix(type, iterableTypeRef)); ref.set(builder); } } @Override @RequiredReadAction public void visitTypeCastExpression(CSharpTypeCastExpressionImpl expression) { DotNetType type = expression.getType(); DotNetTypeRef castTypeRef = type.toTypeRef(); if(castTypeRef == DotNetTypeRef.ERROR_TYPE) { return; } DotNetExpression innerExpression = expression.getInnerExpression(); if(innerExpression == null) { return; } DotNetTypeRef expressionTypeRef = innerExpression.toTypeRef(false); CSharpTypeUtil.InheritResult inheritResult = CSharpTypeUtil.isInheritable(expressionTypeRef, castTypeRef, expression, CSharpCastType.EXPLICIT); if(!inheritResult.isSuccess()) { inheritResult = CSharpTypeUtil.isInheritable(expressionTypeRef, castTypeRef, expression, CSharpCastType.IMPLICIT); if(!inheritResult.isSuccess()) { CompilerCheckBuilder builder = newBuilder(type, formatTypeRef(expressionTypeRef, expression), formatTypeRef(castTypeRef, expression)); if(EarlyAccessProgramManager.is(CS0030TypeCast.class)) { ref.set(builder); } } else if(inheritResult.isConversion()) { CompilerCheckBuilder builder = newBuilder(innerExpression); builder.setTextAttributesKey(CSharpHighlightKey.IMPLICIT_OR_EXPLICIT_CAST); builder.setText(CSharpErrorBundle.message("impicit.cast.from.0.to.1", formatTypeRef(expressionTypeRef, expression), formatTypeRef(castTypeRef, expression))); builder.setHighlightInfoType(HighlightInfoType.INFORMATION); ref.set(builder); } } else if(inheritResult.isConversion()) { CompilerCheckBuilder builder = newBuilder(type); builder.setTextAttributesKey(CSharpHighlightKey.IMPLICIT_OR_EXPLICIT_CAST); builder.setText(CSharpErrorBundle.message("explicit.cast.from.0.to.1", formatTypeRef(expressionTypeRef, expression), formatTypeRef(castTypeRef, expression))); builder.setHighlightInfoType(HighlightInfoType.INFORMATION); ref.set(builder); } } }); return ref.get(); } }