/*
 * 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.lang.psi.impl.source;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.RecursionManager;
import com.intellij.psi.PsiElement;
import consulo.annotations.RequiredReadAction;
import consulo.dotnet.psi.DotNetExpression;
import consulo.dotnet.psi.DotNetType;
import consulo.dotnet.psi.DotNetVariable;
import consulo.dotnet.resolve.DotNetTypeRef;

/**
 * @author VISTALL
 * @since 06.01.14.
 */
public abstract class CSharpVariableImpl extends CSharpMemberImpl implements DotNetVariable
{
	private static final CSharpTypeRefCacher<CSharpVariableImpl> ourCacheSystem = new CSharpTypeRefCacher<CSharpVariableImpl>(true)
	{
		@RequiredReadAction
		@NotNull
		@Override
		protected DotNetTypeRef toTypeRefImpl(CSharpVariableImpl element, boolean resolveFromParentOrInitializer)
		{
			return element.toTypeRefImpl(resolveFromParentOrInitializer);
		}
	};

	public CSharpVariableImpl(@NotNull ASTNode node)
	{
		super(node);
	}

	@RequiredReadAction
	@Nullable
	@Override
	public DotNetExpression getInitializer()
	{
		return findChildByClass(DotNetExpression.class);
	}

	@RequiredReadAction
	@NotNull
	@Override
	public DotNetTypeRef toTypeRef(boolean resolveFromInitializer)
	{
		return CSharpTypeRefCacher.ENABLED ? ourCacheSystem.toTypeRef(this, resolveFromInitializer) : toTypeRefImpl(resolveFromInitializer);
	}

	@RequiredReadAction
	@NotNull
	public DotNetTypeRef toTypeRefImpl(boolean resolveFromInitializer)
	{
		DotNetType type = getType();
		if(type == null)
		{
			return DotNetTypeRef.ERROR_TYPE;
		}

		DotNetTypeRef runtimeType = type.toTypeRef();
		if(resolveFromInitializer && runtimeType == DotNetTypeRef.AUTO_TYPE)
		{
			final DotNetExpression initializer = getInitializer();
			if(initializer == null)
			{
				return DotNetTypeRef.ERROR_TYPE;
			}

			DotNetTypeRef resolvedTypeRef = RecursionManager.doPreventingRecursion(this, false, () -> initializer.toTypeRef(true));
			return resolvedTypeRef == null ? DotNetTypeRef.AUTO_TYPE : resolvedTypeRef;
		}
		else
		{
			return runtimeType;
		}
	}

	@RequiredReadAction
	@Nullable
	@Override
	public PsiElement getConstantKeywordElement()
	{
		return null;
	}

	@RequiredReadAction
	@Override
	public boolean isConstant()
	{
		return false;
	}
}

@@ -758,59 +758,8 @@
 de;%0A
-import com.intellij.openapi.util.RecursionManager;%0A
 impo
@@ -790,16 +790,16 @@
 lement;%0A
+
 import c
@@ -1511,16 +1511,121 @@
 %09%7D%0A%09%7D;%0A%0A
+%09private final ThreadLocal%3CBoolean%3E myTypeRefProcessing = ThreadLocal.withInitial(() -%3E Boolean.FALSE);%0A%0A
 %09public 
@@ -2539,97 +2539,150 @@
 %0A%09%09%09
-DotNetTypeRef resolvedTypeRef = RecursionManager.doPreventingRecursion(this, false, () -%3E
+if(myTypeRefProcessing.get())%0A%09%09%09%7B%0A%09%09%09%09return DotNetTypeRef.AUTO_TYPE;%0A%09%09%09%7D%0A%0A%09%09%09try%0A%09%09%09%7B%0A%09%09%09%09myTypeRefProcessing.set(Boolean.TRUE);%0A%09%09%09%09return
  ini
@@ -2709,89 +2709,79 @@
 rue)
-)
 ;%0A%09%09%09
-return resolvedTypeRef == null ? DotNetTypeRef.AUTO_TYPE : resolvedTypeRef;
+%7D%0A%09%09%09finally%0A%09%09%09%7B%0A%09%09%09%09myTypeRefProcessing.set(Boolean.FALSE);%0A%09%09%09%7D
 %0A%09%09%7D

remove guard