Package com.intellij.coldFusion.model.psi

Source Code of com.intellij.coldFusion.model.psi.CfmlReferenceExpression

/*
* Copyright 2000-2013 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 com.intellij.coldFusion.model.psi;

import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.coldFusion.UI.CfmlLookUpItemUtil;
import com.intellij.coldFusion.model.CfmlUtil;
import com.intellij.coldFusion.model.files.CfmlFile;
import com.intellij.coldFusion.model.lexer.CfmlTokenTypes;
import com.intellij.coldFusion.model.lexer.CfscriptTokenTypes;
import com.intellij.diagnostic.LogMessageEx;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Attachment;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.CheckUtil;
import com.intellij.psi.impl.DebugUtil;
import com.intellij.psi.scope.JavaScopeProcessorEvent;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.PlatformIcons;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
* Created by Lera Nikolaenko
* Date: 11.02.2009
*/
public class CfmlReferenceExpression extends AbstractQualifiedReference<CfmlReferenceExpression>
  implements CfmlReference, CfmlExpression, CfmlTypedElement {
  private static final Logger LOG = Logger.getInstance(CfmlReferenceExpression.class.getName());

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

  @Override
  protected boolean processUnqualifiedVariants(PsiScopeProcessor processor) {
    PsiFile containingFile = getContainingFile();
    if (containingFile instanceof CfmlFile) {
      CfmlComponent componentDefinition = ((CfmlFile)containingFile).getComponentDefinition();

      // process functions
      // functions should be processed !first! as explicitly defined getter overlaps the implicit one
      CfmlFunction[] functions;
      if (componentDefinition != null) {
        functions = componentDefinition.getFunctionsWithSupers(this.getFirstChild() instanceof CfmlSuperComponentReference);
      }
      else {
        PsiFile file = this.getContainingFile();
        if (file instanceof CfmlFile) {
          functions = ((CfmlFile)file).getGlobalFunctions().toArray(CfmlFunction.EMPTY_ARRAY);
        }
        else {
          functions = CfmlFunction.EMPTY_ARRAY;
        }
      }
      for (CfmlFunction function : functions) {
        if (!processor.execute(function, ResolveState.initial())) {
          return false;
        }
      }
      // process properties
      if (componentDefinition != null) {
        CfmlProperty[] propertiesWithSupers =
          componentDefinition.getPropertiesWithSupers(this.getFirstChild() instanceof CfmlSuperComponentReference);
        for (CfmlProperty property : propertiesWithSupers) {
          if (!processor.execute(property, ResolveState.initial())) {
            return false;
          }
        }
      }
    }
    return super.processUnqualifiedVariants(processor);
  }

  @Override
  protected boolean processVariantsInner(PsiScopeProcessor processor) {
    CfmlTypedElement typedOwner = CfmlPsiUtil.getTypedQualifierInner(this);
    PsiType type = null;
    if (typedOwner != null) {
      type = typedOwner.getPsiType();
    }
    else {
      return processUnqualifiedVariants(processor);
    }
    // CfmlReferenceExpression qualifier = CfmlPsiUtil.getQualifierInner(this);
    if (type instanceof PsiClassType) {
      PsiClass psiClass;
      if (type instanceof CfmlFunctionCallExpression.PsiClassStaticType) {
        psiClass = PsiUtil.resolveClassInType(((CfmlFunctionCallExpression.PsiClassStaticType)type).getRawType());
        processor.handleEvent(JavaScopeProcessorEvent.START_STATIC, null);
      }
      else {
        psiClass = PsiUtil.resolveClassInType(type);
      }
      processor.handleEvent(CfmlVariantsProcessor.CfmlProcessorEvent.SET_INITIAL_CLASS, psiClass);
      if (psiClass != null && !psiClass.processDeclarations(processor, ResolveState.initial(), null, this)) {
        return false;
      }
    }
    else if (type instanceof CfmlComponentType) {
      Collection<CfmlComponent> components = ((CfmlComponentType)type).resolve();

      for (CfmlComponent component : components) {
        if (!component.processDeclarations(processor, ResolveState.initial(), null, this)) {
          return false;
        }
      }
    }
    if (typedOwner instanceof CfmlFunctionCallExpression) {
      typedOwner = ((CfmlFunctionCallExpression)typedOwner).getReferenceExpression();
    }
    if (typedOwner instanceof CfmlReference) {
      final PsiElement psiElement = ((CfmlReference)typedOwner).resolve();
      return psiElement == null || psiElement.processDeclarations(processor, ResolveState.initial(), null, this);
    }
    return true;
  }

  @Override
  public boolean isReferenceTo(PsiElement element) {
    if (element instanceof CfmlProperty && element.getContainingFile() == getContainingFile()) {
      String name = ((CfmlProperty)element).getName();
      String referenceText = getText();

      if ((referenceText.toLowerCase().startsWith("get") ||
           referenceText.toLowerCase().startsWith("set")) &&
          referenceText.substring(3).equalsIgnoreCase(name)) {
        return true;
      }
      else {
        return false;
      }
    }

    final PsiManager manager = getManager();
    for (final ResolveResult result : multiResolve(false)) {
      final PsiElement target = result.getElement();
      if (manager.areElementsEquivalent(element, target)) {
        return true;
      }
    }
    return false;
    //return super.isReferenceTo(element);    //To change body of overridden methods use File | Settings | File Templates.
  }

  protected ResolveResult[] resolveInner() {
    final String referenceName = getReferenceName();
    if (referenceName == null) {
      return ResolveResult.EMPTY_ARRAY;
    }

    final CfmlVariantsProcessor<ResolveResult> processor = new CfmlVariantsProcessor<ResolveResult>(this, getParent(), referenceName) {
      //Map<String, PsiNamedElement> myVariables = new HashMap<String, PsiNamedElement>();

      protected ResolveResult execute(final PsiNamedElement element, final boolean error) {
        return new PsiElementResolveResult(element, false);
      }
    };

    boolean ifContinue = true;

    final PsiElement parent = getParent();
    if (parent instanceof CfmlAssignmentExpression) {
      CfmlAssignmentExpression assignment = (CfmlAssignmentExpression)parent;
      CfmlVariable var = assignment.getAssignedVariable();
      if (var != null && assignment.getAssignedVariableElement() == this) {
        ifContinue = processor.execute(var, ResolveState.initial());
      }
    }

    if (ifContinue) {
      processVariantsInner(processor);
    }
    final ResolveResult[] variantsResults = processor.getVariants(ResolveResult.EMPTY_ARRAY);
    List<ResolveResult> results = new ArrayList<ResolveResult>();
    for (ResolveResult variantsResult : variantsResults) {
      if (variantsResult.getElement() != null) {
        PsiElement parentRef = variantsResult.getElement().getParent();
        if (!(parentRef instanceof CfmlReferenceExpression) ||
            (variantsResult.getElement() instanceof CfmlAssignmentExpression.AssignedVariable &&
             CfmlUtil.hasEqualScope(this, (CfmlReferenceExpression)parentRef))) {
          results.add(variantsResult);
        }
      }
    }
    if (results.isEmpty()) {
      return ResolveResult.EMPTY_ARRAY;
    }
    // resolve to truly declaration if found, otherwise resolve to the nearest assignment
    if (results.size() > 1) {
      ResolveResult result = results.get(results.size() - 1);
      PsiElement element = result.getElement();
      if (element instanceof CfmlVariable && ((CfmlVariable)element).isTrulyDeclaration()) {
        return new ResolveResult[]{result};
      }
    }
    return new ResolveResult[]{results.get(0)};
  }

  @NotNull
  protected CfmlReferenceExpression parseReference(String newText) {
    return CfmlPsiUtil.createReferenceExpression(newText, getProject());
  }

  protected PsiElement getSeparator() {
    return findChildByType(CfscriptTokenTypes.POINT);
  }

  @Override
  public TextRange getRangeInElement() {
    if (getScope() != null) {
      return new TextRange(0, getTextLength());
    }
    return super.getRangeInElement();
  }

  private static boolean checkType(@Nullable PsiElement element, IElementType type) {
    if (element == null) {
      return false;
    }
    ASTNode node = element.getNode();
    if (node != null && node.getElementType().equals(type)) {
      return true;
    }
    return false;
  }

  @Nullable
  public PsiElement getScope() {
    PsiElement identifier = findChildByType(CfscriptTokenTypes.IDENTIFIER);
    if (identifier != null) {
      PsiElement prevSubling = identifier.getPrevSibling();
      if (prevSubling != null &&
          checkType(prevSubling, CfscriptTokenTypes.POINT) &&
          checkType(prevSubling.getPrevSibling(), CfscriptTokenTypes.SCOPE_KEYWORD)) {
        return prevSubling.getPrevSibling();
      }
    }
    return null;
  }

  protected PsiElement getReferenceNameElement() {
    PsiElement identifier = findChildByType(CfscriptTokenTypes.IDENTIFIER);
    if (identifier == null) {
      return findChildByType(CfmlTokenTypes.STRING_TEXT);
    }
    /*
    if (getScope() != null) {
      return identifier.getParent();
    }
    */
    return identifier;
  }

  @NotNull
  public Object[] getVariants() {
    final CfmlVariantsProcessor<PsiNamedElement> processor = new CfmlVariantsProcessor<PsiNamedElement>(this, getParent(), null) {
      Set<String> myVariablesNames = new HashSet<String>();

      protected PsiNamedElement execute(final PsiNamedElement element, final boolean error) {
        if (element instanceof CfmlVariable) {
          if (myVariablesNames.add(element.getName())) {
            return element;
          }
          return null;
        }
        else {
          // only variables can be scoped
          PsiElement scope = getScope();
          if (scope != null && !scope.getText().equalsIgnoreCase("this")) {
            return null;
          }
        }
        return element;
      }
    };
    processVariantsInner(processor);
    PsiNamedElement[] variants = processor.getVariants(PsiNamedElement.EMPTY_ARRAY);
    HashSet<LookupElement> result = new HashSet<LookupElement>();
    for (PsiNamedElement namedElement : variants) {
      if (namedElement instanceof CfmlProperty) {
        final String capitalizedName = StringUtil.capitalize(StringUtil.notNullize(namedElement.getName()));
        if (((CfmlProperty)namedElement).hasGetter() ||
            (namedElement.getParent() instanceof CfmlComponent &&
             (((CfmlComponent)namedElement.getParent()).hasImplicitAccessors() ||
              ((CfmlComponent)namedElement.getParent()).isPersistent()))) {
          result.add(LookupElementBuilder.create(namedElement, "get" + capitalizedName + "()").withCaseSensitivity(false)
                       .withIcon(PlatformIcons.METHOD_ICON));
        }
        if (((CfmlProperty)namedElement).hasSetter() ||
            (namedElement.getParent() instanceof CfmlComponent &&
             (((CfmlComponent)namedElement.getParent()).hasImplicitAccessors() ||
              ((CfmlComponent)namedElement.getParent()).isPersistent()))) {
          result.add(LookupElementBuilder.create(namedElement, "set" + capitalizedName + "()").withCaseSensitivity(false)
                       .withIcon(PlatformIcons.METHOD_ICON));
        }
      }
    }

    result.addAll(ContainerUtil.map2Set(variants, new Function<PsiNamedElement, LookupElement>() {
      public LookupElement fun(final PsiNamedElement element) {
        PsiElement scope = getScope();
        return CfmlLookUpItemUtil.namedElementToLookupItem(element, scope != null ? scope.getText() : null);
      }
    }));
    return result.toArray();
  }

  public PsiType getPsiType() {
    if (getParent() instanceof CfmlFunctionCallExpression) {
      final PsiType type = ((CfmlFunctionCallExpression)getParent()).getExternalType();
      if (type != null) {
        return type;
      }
    }
    final PsiElement element = resolve();
    if (element instanceof CfmlVariable) {
      if ((element instanceof CfmlAssignmentExpression.AssignedVariable)) {
        CfmlExpression rightExpr = ((CfmlAssignmentExpression.AssignedVariable)element).getRightHandExpr();
        if (rightExpr == this || (rightExpr instanceof CfmlFunctionCallExpression &&
                                  ((CfmlFunctionCallExpression)rightExpr).getExternalType() == null &&
                                  ((CfmlFunctionCallExpression)rightExpr).getReferenceExpression() == this)) {
          LOG.error(LogMessageEx.createEvent("CFML parsing problem",
                                             "Please report the problem to JetBrains with the file attached\nProblem at" +
                                             (rightExpr != null ? rightExpr.getText() : null) +
                                             "\n" +
                                             DebugUtil.currentStackTrace(),
                                             "CFML parsing problem",
                                             "CFML parsing problem",
                                             new Attachment("problem.cfml", element.getContainingFile().getText())));
          return null;
        }
      }
      return ((CfmlVariable)element).getPsiType();
    }
    if (element instanceof PsiMethod) {
      PsiMethod method = (PsiMethod)element;
      return method.getReturnType();
    }
    if (element instanceof CfmlFunction) {
      return ((CfmlFunction)element).getReturnType();
    }
    return null;
  }

  @Override
  public String getReferenceName() {
    PsiElement identifier = getReferenceNameElement();
    return identifier != null ? identifier.getText() : "";
  }

  @Override
  public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
    CheckUtil.checkWritable(this);

    PsiElement newElement;

    final PsiElement referenceNameElement = getReferenceNameElement();
    if (referenceNameElement != null) {
      final ASTNode referenceNode = referenceNameElement.getNode();
      if (referenceNode == null) {
        return this;
      }
      if (referenceNode.getElementType() == CfmlTokenTypes.STRING_TEXT) {
        newElement = CfmlPsiUtil.createConstantString(newElementName, getProject());
      }
      else {
        newElement = CfmlPsiUtil.createIdentifier(newElementName, getProject());
      }
      //noinspection ConstantConditions
      getNode().replaceChild(referenceNode, newElement.getNode());
    }

    return this;
  }

  public String toString() {
    return getNode().getElementType().toString();
  }
}
TOP

Related Classes of com.intellij.coldFusion.model.psi.CfmlReferenceExpression

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.