/* * 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.debugger.expressionEvaluator; import java.util.Map; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import com.intellij.openapi.application.ReadAction; import consulo.annotations.RequiredReadAction; import consulo.csharp.ide.debugger.CSharpEvaluateContext; import consulo.csharp.ide.debugger.CSharpStaticValueProxy; import consulo.csharp.lang.psi.CSharpTypeDeclaration; import consulo.csharp.lang.psi.impl.DotNetTypes2; import consulo.dotnet.debugger.DotNetDebuggerSearchUtil; import consulo.dotnet.debugger.proxy.DotNetFieldOrPropertyProxy; import consulo.dotnet.debugger.proxy.DotNetNotSuspendedException; import consulo.dotnet.debugger.proxy.DotNetThrowValueException; import consulo.dotnet.debugger.proxy.DotNetTypeProxy; import consulo.dotnet.debugger.proxy.value.DotNetNullValueProxy; import consulo.dotnet.debugger.proxy.value.DotNetObjectValueProxy; import consulo.dotnet.debugger.proxy.value.DotNetStructValueProxy; import consulo.dotnet.debugger.proxy.value.DotNetValueProxy; import consulo.dotnet.psi.DotNetModifier; import consulo.dotnet.psi.DotNetModifierListOwner; import consulo.dotnet.psi.DotNetQualifiedElement; /** * @author VISTALL * @since 09.03.2016 */ public abstract class FieldOrPropertyEvaluator<T extends DotNetQualifiedElement & DotNetModifierListOwner, M extends DotNetFieldOrPropertyProxy> extends Evaluator { @Nullable private CSharpTypeDeclaration myTypeDeclaration; protected T myElement; public FieldOrPropertyEvaluator(@Nullable CSharpTypeDeclaration typeDeclaration, T element) { myTypeDeclaration = typeDeclaration; myElement = element; } protected abstract boolean isMyMirror(@NotNull DotNetFieldOrPropertyProxy mirror); protected abstract boolean invoke(@NotNull M mirror, @NotNull CSharpEvaluateContext context, @Nullable DotNetValueProxy popValue) throws DotNetThrowValueException, DotNetNotSuspendedException; @Nullable @RequiredReadAction public String getName() { return myElement.getName(); } @Override public void evaluate(@NotNull CSharpEvaluateContext context) throws DotNetThrowValueException, DotNetNotSuspendedException { DotNetValueProxy popValue = context.popValue(); if(popValue == null) { throw new IllegalArgumentException("no pop value"); } DotNetTypeProxy typeMirror; if(myTypeDeclaration == null) { typeMirror = popValue.getType(); } else { typeMirror = ReadAction.compute(() -> findTypeMirror(context, myTypeDeclaration)); } if(typeMirror == null) { throw new IllegalArgumentException("cant calculate type"); } String name = ReadAction.compute(this::getName); if(name == null) { throw new IllegalArgumentException("invalid name"); } if(popValue instanceof DotNetStructValueProxy) { Map<DotNetFieldOrPropertyProxy, DotNetValueProxy> values = ((DotNetStructValueProxy) popValue).getValues(); for(Map.Entry<DotNetFieldOrPropertyProxy, DotNetValueProxy> entry : values.entrySet()) { DotNetFieldOrPropertyProxy key = entry.getKey(); if(isMyMirror(key)) { DotNetValueProxy value = entry.getValue(); if(key.getName().equals(name)) { context.pull(value, key); return; } } } } else if(popValue == CSharpStaticValueProxy.INSTANCE && ReadAction.compute(() -> myElement.hasModifier(DotNetModifier.STATIC))) { if(invokeFieldOrProperty(context, name, popValue, typeMirror)) { return; } } else { DotNetObjectValueProxy objectValueMirror = ObjectValueMirrorUtil.extractObjectValueMirror(popValue); if(objectValueMirror != null && invokeFieldOrProperty(context, name, objectValueMirror, typeMirror)) { return; } if(popValue instanceof DotNetNullValueProxy) { throw new DotNetThrowValueException(DotNetTypes2.System.NullReferenceException, null); } if(tryEvaluateNonObjectValue(context, popValue)) { return; } } throw new IllegalArgumentException("can't find member with name '" + name + "' from parent : " + typeMirror.getFullName()); } protected boolean tryEvaluateNonObjectValue(CSharpEvaluateContext context, DotNetValueProxy value) { return false; } @SuppressWarnings("unchecked") private boolean invokeFieldOrProperty(@NotNull CSharpEvaluateContext context, @NotNull String name, @NotNull DotNetValueProxy popValue, @NotNull DotNetTypeProxy typeMirror) throws DotNetThrowValueException, DotNetNotSuspendedException { DotNetFieldOrPropertyProxy[] fieldOrPropertyMirrors = DotNetDebuggerSearchUtil.getFieldAndProperties(typeMirror, true); for(DotNetFieldOrPropertyProxy fieldOrPropertyMirror : fieldOrPropertyMirrors) { if(isMyMirror(fieldOrPropertyMirror) && fieldOrPropertyMirror.getName().equals(name) && invoke((M) fieldOrPropertyMirror, context, substituteStaticContext(popValue))) { return true; } } return false; } }