/*
* Copyright 2013-2015 Sergey Ignatov, Alexander Zolotov, Florin Patan
*
* 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 com.goide.psi.impl;
import com.goide.psi.*;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class GoVarProcessor extends GoScopeProcessorBase {
private final boolean myImShortVarDeclaration;
private final PsiElement myParentGuard;
@Nullable private final GoCompositeElement myScope;
public GoVarProcessor(@NotNull PsiElement origin, boolean completion) {
this(origin, origin, completion, false);
}
public GoVarProcessor(@NotNull PsiElement requestedName, @NotNull PsiElement origin, boolean completion, boolean delegate) {
super(requestedName, origin, completion);
myImShortVarDeclaration = PsiTreeUtil.getParentOfType(origin, GoShortVarDeclaration.class) != null && !delegate;
myParentGuard = origin.getParent() instanceof GoTypeSwitchGuard ? origin.getParent() : null;
myScope = getScope(origin);
}
@Override
protected boolean add(@NotNull GoNamedElement o) {
PsiElement commonParent = PsiTreeUtil.findCommonParent(o, myOrigin);
if (commonParent instanceof GoRangeClause || commonParent instanceof GoTypeSwitchGuard) return true;
PsiElement p = o.getParent();
boolean inVarOrRange = PsiTreeUtil.getParentOfType(o, GoVarDeclaration.class) != null || p instanceof GoRangeClause;
boolean differentBlocks = differentBlocks(o);
boolean inShortVar = PsiTreeUtil.getParentOfType(o, GoShortVarDeclaration.class, GoRecvStatement.class) != null;
if (inShortVar && differentBlocks && myImShortVarDeclaration) return true;
if (differentBlocks && inShortVar && !inVarOrRange && getResult() != null && !myIsCompletion) return true;
if (inShortVar && fromNotAncestorBlock(o)) return true;
if (myParentGuard != null && o instanceof GoVarDefinition && p.isEquivalentTo(myParentGuard)) return true;
return super.add(o);
}
private boolean fromNotAncestorBlock(@NotNull GoNamedElement o) {
return (myScope instanceof GoExprCaseClause || myScope instanceof GoCommClause) &&
!PsiTreeUtil.isAncestor(getScope(o), myOrigin, false);
}
private boolean differentBlocks(@Nullable GoNamedElement o) {
return !Comparing.equal(myScope, getScope(o));
}
@Nullable
public static GoCompositeElement getScope(@Nullable PsiElement o) {
GoForStatement forStatement = PsiTreeUtil.getParentOfType(o, GoForStatement.class);
if (forStatement != null) return forStatement.getBlock();
GoIfStatement ifStatement = PsiTreeUtil.getParentOfType(o, GoIfStatement.class);
if (ifStatement != null) return ifStatement.getBlock();
GoElseStatement elseStatement = PsiTreeUtil.getParentOfType(o, GoElseStatement.class);
if (elseStatement != null) return elseStatement.getBlock();
GoExprCaseClause exprCaseClause = PsiTreeUtil.getParentOfType(o, GoExprCaseClause.class);
if (exprCaseClause != null) return exprCaseClause;
GoCommClause commClause = PsiTreeUtil.getParentOfType(o, GoCommClause.class);
if (commClause != null) return commClause;
return PsiTreeUtil.getParentOfType(o, GoBlock.class);
}
@Override
protected boolean crossOff(@NotNull PsiElement e) {
return !(e instanceof GoVarDefinition) &&
!(e instanceof GoParamDefinition) &&
!(e instanceof GoReceiver) &&
!(e instanceof GoFieldDefinition) &&
!(e instanceof GoAnonymousFieldDefinition) &&
!(e instanceof GoConstDefinition);
}
}