Package org.intellij.erlang.psi.impl

Source Code of org.intellij.erlang.psi.impl.ErlangFileImpl

/*
* Copyright 2012-2014 Sergey Ignatov
*
* 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 org.intellij.erlang.psi.impl;

import com.intellij.extapi.psi.PsiFileBase;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNameIdentifierOwner;
import com.intellij.psi.PsiReference;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.stubs.StubTree;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import gnu.trove.THashMap;
import org.intellij.erlang.ErlangFileType;
import org.intellij.erlang.ErlangLanguage;
import org.intellij.erlang.ErlangTypes;
import org.intellij.erlang.parser.ErlangParserUtil;
import org.intellij.erlang.psi.*;
import org.intellij.erlang.stubs.ErlangCallbackSpecStub;
import org.intellij.erlang.stubs.ErlangFileStub;
import org.intellij.erlang.stubs.types.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

public class ErlangFileImpl extends PsiFileBase implements ErlangFile, PsiNameIdentifierOwner {
  public ErlangFileImpl(@NotNull FileViewProvider viewProvider) {
    super(viewProvider, ErlangLanguage.INSTANCE);
  }

  @Nullable
  @Override
  public ErlangModule getModule() {
    ErlangFileStub stub = getStub();
    if (stub != null) {
      return ArrayUtil.getFirstElement(stub.getChildrenByType(ErlangTypes.ERL_MODULE, ErlangModuleStubElementType.ARRAY_FACTORY));
    }

    List<ErlangAttribute> attributes = PsiTreeUtil.getChildrenOfTypeAsList(this, ErlangAttribute.class);
    for (ErlangAttribute attribute : attributes) {
      ErlangModule module = attribute.getModule();
      if (module != null) {
        return module;
      }
    }
    return null;
  }

  @Override
  public PsiElement setName(@NotNull String name) throws IncorrectOperationException {
    String nameWithoutExtension = FileUtil.getNameWithoutExtension(name);

    for (ErlangAttribute moduleAttributes : getAttributes()) {
      ErlangModule module = moduleAttributes.getModule();
      if (module != null) {
        // todo: use module with dependencies scope
        if (!DumbService.isDumb(getProject())) {
          Query<PsiReference> search = ReferencesSearch.search(module, GlobalSearchScope.allScope(module.getProject()));
          for (PsiReference psiReference : search) {
            psiReference.handleElementRename(nameWithoutExtension);
          }
        }
        module.setName(nameWithoutExtension);
      }
    }

    return super.setName(name);
  }

  private CachedValue<List<ErlangRule>> myRulesValue =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<List<ErlangRule>>() {
      @Override
      public Result<List<ErlangRule>> compute() {
        return Result.create(calcRules(), ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<List<ErlangFunction>> myFunctionValue =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<List<ErlangFunction>>() {
      @Override
      public Result<List<ErlangFunction>> compute() {
        return Result.create(calcFunctions(), ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<Set<ErlangFunction>> myExportedFunctionValue =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<Set<ErlangFunction>>() {
      @Override
      public Result<Set<ErlangFunction>> compute() {
        ErlangFileImpl erlangFile = ErlangFileImpl.this;
        return Result.create(calcExportedFunctions(), erlangFile);
      }
    }, false);
  private CachedValue<List<ErlangAttribute>> myAttributeValue =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<List<ErlangAttribute>>() {
      @Override
      public Result<List<ErlangAttribute>> compute() {
        return Result.create(calcAttributes(), ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<List<ErlangRecordDefinition>> myRecordValue =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<List<ErlangRecordDefinition>>() {
      @Override
      public Result<List<ErlangRecordDefinition>> compute() {
        return Result.create(calcRecords(), ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<List<ErlangInclude>> myIncludeValue =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<List<ErlangInclude>>() {
      @Override
      public Result<List<ErlangInclude>> compute() {
        return Result.create(calcIncludes(), ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<List<ErlangIncludeLib>> myIncludeLibValue =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<List<ErlangIncludeLib>>() {
      @Override
      public Result<List<ErlangIncludeLib>> compute() {
        return Result.create(calcIncludeLibs(), ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<MultiMap<String, ErlangFunction>> myFunctionsMap =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<MultiMap<String, ErlangFunction>>() {
      @Override
      public Result<MultiMap<String, ErlangFunction>> compute() {
        MultiMap<String, ErlangFunction> map = new MultiMap<String, ErlangFunction>();
        for (ErlangFunction function : getFunctions()) {
          map.putValue(function.getName(), function);
        }
        return Result.create(map, ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<Map<String, ErlangRecordDefinition>> myRecordsMap =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<Map<String, ErlangRecordDefinition>>() {
      @Override
      public Result<Map<String, ErlangRecordDefinition>> compute() {
        Map<String, ErlangRecordDefinition> map = new THashMap<String, ErlangRecordDefinition>();
        for (ErlangRecordDefinition record : getRecords()) {
          String recordName = record.getName();
          if (!map.containsKey(recordName)) {
            map.put(recordName, record);
          }
        }
        return Result.create(map, ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<List<ErlangMacrosDefinition>> myMacrosValue =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<List<ErlangMacrosDefinition>>() {
      @Override
      public Result<List<ErlangMacrosDefinition>> compute() {
        return Result.create(calcMacroses(), ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<Map<String, ErlangMacrosDefinition>> myMacrosesMap =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<Map<String, ErlangMacrosDefinition>>() {
      @Override
      public Result<Map<String, ErlangMacrosDefinition>> compute() {
        Map<String, ErlangMacrosDefinition> map = new THashMap<String, ErlangMacrosDefinition>();
        for (ErlangMacrosDefinition macros : getMacroses()) {
          String macrosName = ErlangPsiImplUtil.getName(macros);
          if (!map.containsKey(macrosName)) {
            map.put(macrosName, macros);
          }
        }
        return Result.create(map, ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<List<ErlangTypeDefinition>> myTypeValue =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<List<ErlangTypeDefinition>>() {
      @Override
      public Result<List<ErlangTypeDefinition>> compute() {
        return Result.create(calcTypes(), ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<Map<String, ErlangTypeDefinition>> myTypeMap =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<Map<String, ErlangTypeDefinition>>() {
      @Override
      public Result<Map<String, ErlangTypeDefinition>> compute() {
        Map<String, ErlangTypeDefinition> map = new THashMap<String, ErlangTypeDefinition>();
        for (ErlangTypeDefinition type : getTypes()) {
          String mName = type.getName();
          if (!map.containsKey(mName)) {
            map.put(mName, type);
          }
        }
        return Result.create(map, ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<Map<String, ErlangCallbackSpec>> myCallbackMap =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<Map<String, ErlangCallbackSpec>>() {
      @Nullable
      @Override
      public Result<Map<String, ErlangCallbackSpec>> compute() {
        return Result.create(calcCallbacks(), ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<List<ErlangBehaviour>> myBehavioursValue =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<List<ErlangBehaviour>>() {
      @Override
      public Result<List<ErlangBehaviour>> compute() {
        return Result.create(calcBehaviours(), ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<List<ErlangSpecification>> mySpecificationsValue =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<List<ErlangSpecification>>() {
      @Override
      public Result<List<ErlangSpecification>> compute() {
        return Result.create(calcSpecifications(), ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<Boolean> myExportAll =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<Boolean>() {
      @Override
      public Result<Boolean> compute() {
        return Result.create(calcExportAll(), ErlangFileImpl.this);
      }
    }, false);
  private CachedValue<Set<String>> myExportedFunctionsSignatures =
    CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider<Set<String>>() {
      @Override
      public Result<Set<String>> compute() {
        return Result.create(calcExportedSignatures(), ErlangFileImpl.this);
      }
    }, false);

  @NotNull
  @Override
  public FileType getFileType() {
    return ErlangFileType.MODULE;
  }

  @Nullable
  public ErlangFileStub getStub() {
    StubElement stub = super.getStub();
    if (stub == null) return null;
    return (ErlangFileStub) stub;
  }

  @Override
  public boolean isExported(@NotNull String signature) {
    if (isExportedAll()) return true;
    return myExportedFunctionsSignatures.getValue().contains(signature);
  }

  @NotNull
  private Set<String> calcExportedSignatures() {
    Set<String> result = ContainerUtil.newHashSet();
    for (ErlangAttribute attribute : getAttributes()) {
      ErlangExport export = attribute.getExport();
      ErlangExportFunctions exportFunctions = export != null ? export.getExportFunctions() : null;
      if (exportFunctions == null) continue;
      List<ErlangExportFunction> list = exportFunctions.getExportFunctionList();
      for (ErlangExportFunction exportFunction : list) {
        PsiElement integer = exportFunction.getInteger();
        if (integer == null) continue;
        String s = ErlangPsiImplUtil.getExportFunctionName(exportFunction) + "/" + integer.getText();
        result.add(s);
      }
    }
    return result;
  }

  @Override
  public boolean isExportedAll() {
    //TODO do we use stubs?
    ErlangFileStub stub = getStub();
    if (stub != null) {
      return stub.isExportAll();
    }
    return myExportAll.getValue();
  }

  private Boolean calcExportAll() {
    for (ErlangAttribute attribute : getAttributes()) {
      ErlangAtomAttribute atomAttribute = attribute.getAtomAttribute();
      if (atomAttribute != null) {
        if ("compile".equals(atomAttribute.getQAtom().getText())) {
          ErlangAttrVal attrVal = atomAttribute.getAttrVal();
          if (attrVal != null) {
            List<ErlangExpression> expressionList = attrVal.getExpressionList();
            for (ErlangExpression expression : expressionList) {
              if (expression instanceof ErlangListExpression) {
                for (ErlangExpression e : ((ErlangListExpression) expression).getExpressionList()) {
                  if (e instanceof ErlangMaxExpression && e.getText().equals("export_all")) return true;
                }
              }
              else if (expression instanceof ErlangMaxExpression && expression.getText().equals("export_all")) return true;
            }
          }
        }
      }
    }
    return false;
  }

  @NotNull
  @Override
  public List<ErlangRule> getRules() {
    return myRulesValue.getValue();
  }

  @NotNull
  @Override
  public List<ErlangAttribute> getAttributes() {
    return myAttributeValue.getValue();
  }

  @Nullable
  @Override
  public ErlangCallbackSpec getCallbackByName(@NotNull String fullName) {
    return getCallbackMap().get(fullName);
  }

  @NotNull
  @Override
  public Map<String, ErlangCallbackSpec> getCallbackMap() {
    //TODO do we use stubs?
    ErlangFileStub stub = getStub();
    if (stub != null) {
      Map<String, ErlangCallbackSpec> callbacksMap = new LinkedHashMap<String, ErlangCallbackSpec>();
      for (StubElement child : stub.getChildrenStubs()) {
        if (child instanceof ErlangCallbackSpecStub) {
          String name = ((ErlangCallbackSpecStub) child).getName();
          int arity = ((ErlangCallbackSpecStub) child).getArity();
          callbacksMap.put(name + "/" + arity, ((ErlangCallbackSpecStub) child).getPsi());
        }
      }
      return callbacksMap;
    }

    return myCallbackMap.getValue();
  }

  @NotNull
  private Map<String, ErlangCallbackSpec> calcCallbacks() {
    Map<String, ErlangCallbackSpec> callbacksMap = new LinkedHashMap<String, ErlangCallbackSpec>();

    for (ErlangAttribute a : getAttributes()) {
      ErlangCallbackSpec spec = a.getCallbackSpec();
      if (spec != null) {
        String name = ErlangPsiImplUtil.getCallbackSpecName(spec);
        int arity = ErlangPsiImplUtil.getCallBackSpecArguments(spec).size();
        callbacksMap.put(name + "/" + arity, spec);
      }
    }
    return callbacksMap;
  }
 
  @NotNull
  @Override
  public List<ErlangFunction> getFunctions() {
    return myFunctionValue.getValue();
  }

  @NotNull
  @Override
  public Collection<ErlangFunction> getExportedFunctions() {
    return myExportedFunctionValue.getValue();
  }

  private Set<ErlangFunction> calcExportedFunctions() {
    if (isExportedAll()) {
      return ContainerUtil.newHashSet(getFunctions());
    }
    final Set<ErlangFunction> result = new HashSet<ErlangFunction>();
    processChildrenDummyAware(this, new Processor<PsiElement>() {
      @Override
      public boolean process(PsiElement psiElement) {
        if (psiElement instanceof ErlangFunction) {
          if (((ErlangFunction) psiElement).isExported()) {
            result.add((ErlangFunction) psiElement);
          }
        }
        return true;
      }
    });
    return result;
  }

  @Nullable
  @Override
  public ErlangFunction getFunction(@NotNull String name, int argsCount) {
    MultiMap<String, ErlangFunction> value = myFunctionsMap.getValue();
    return getFunctionFromMap(value, name, argsCount);
  }

  @Override
  @NotNull
  public Collection<ErlangFunction> getFunctionsByName(@NotNull String name) {
    return myFunctionsMap.getValue().get(name);
  }

  @Nullable
  private static ErlangFunction getFunctionFromMap(MultiMap<String, ErlangFunction> value, String name, final int argsCount) {
    Collection<ErlangFunction> candidates = value.get(name);

    return ContainerUtil.getFirstItem(ContainerUtil.filter(candidates, new Condition<ErlangFunction>() {
      @Override
      public boolean value(ErlangFunction erlangFunction) {
        return erlangFunction.getArity() == argsCount;
      }
    }));
  }

  @NotNull
  @Override
  public List<ErlangRecordDefinition> getRecords() {
    return myRecordValue.getValue();
  }

  @NotNull
  @Override
  public List<ErlangTypeDefinition> getTypes() {
    return myTypeValue.getValue();
  }

  private List<ErlangTypeDefinition> calcTypes() {
    ErlangFileStub stub = getStub();
    if (stub != null) {
      return getChildrenByType(stub, ErlangTypes.ERL_TYPE_DEFINITION, ErlangTypeDefinitionElementType.ARRAY_FACTORY);
    }

    final List<ErlangTypeDefinition> result = new ArrayList<ErlangTypeDefinition>();
    processChildrenDummyAware(this, new Processor<PsiElement>() {
      @Override
      public boolean process(PsiElement psiElement) {
        if (psiElement instanceof ErlangTypeDefinition) {
          result.add((ErlangTypeDefinition) psiElement);
        }
        return true;
      }
    });
    return result;
  }

  private static <E extends PsiElement> List<E> getChildrenByType(ErlangFileStub stub, IElementType elementType, ArrayFactory<E> f) {
    return Arrays.asList(stub.getChildrenByType(elementType, f));
  }

  @Override
  public ErlangTypeDefinition getType(@NotNull String name) {
    return myTypeMap.getValue().get(name);
  }

  @NotNull
  @Override
  public List<ErlangMacrosDefinition> getMacroses() {
    return myMacrosValue.getValue();
  }

  private List<ErlangMacrosDefinition> calcMacroses() {
    ErlangFileStub stub = getStub();
    if (stub != null) {
      return getChildrenByType(stub, ErlangTypes.ERL_MACROS_DEFINITION, ErlangMacrosDefinitionElementType.ARRAY_FACTORY);
    }

    final List<ErlangMacrosDefinition> result = new ArrayList<ErlangMacrosDefinition>();
    processChildrenDummyAware(this, new Processor<PsiElement>() {
      @Override
      public boolean process(PsiElement psiElement) {
        if (psiElement instanceof ErlangMacrosDefinition) {
          result.add((ErlangMacrosDefinition) psiElement);
        }
        return true;
      }
    });
    return result;
  }

  @Override
  public ErlangMacrosDefinition getMacros(@NotNull String name) {
    return myMacrosesMap.getValue().get(name);
  }

  private List<ErlangRecordDefinition> calcRecords() {
    ErlangFileStub stub = getStub();
    if (stub != null) {
      return getChildrenByType(stub, ErlangTypes.ERL_RECORD_DEFINITION, ErlangRecordDefinitionElementType.ARRAY_FACTORY);
    }

    final List<ErlangRecordDefinition> result = new ArrayList<ErlangRecordDefinition>();
    processChildrenDummyAware(this, new Processor<PsiElement>() {
      @Override
      public boolean process(PsiElement psiElement) {
        if (psiElement instanceof ErlangRecordDefinition) {
          result.add((ErlangRecordDefinition) psiElement);
        }
        return true;
      }
    });
    return result;
  }

  @NotNull
  @Override
  public List<ErlangInclude> getIncludes() {
    return myIncludeValue.getValue();
  }

  @NotNull
  @Override
  public List<ErlangIncludeLib> getIncludeLibs() {
    return myIncludeLibValue.getValue();
  }

  private List<ErlangInclude> calcIncludes() {
    ErlangFileStub stub = getStub();
    if (stub != null) {
      return getChildrenByType(stub, ErlangTypes.ERL_INCLUDE, ErlangIncludeElementType.ARRAY_FACTORY);
    }

    final List<ErlangInclude> result = new ArrayList<ErlangInclude>();
    processChildrenDummyAware(this, new Processor<PsiElement>() {
      @Override
      public boolean process(PsiElement psiElement) {
        if (psiElement instanceof ErlangInclude) {
          result.add((ErlangInclude) psiElement);
        }
        return true;
      }
    });
    return result;
  }

  private List<ErlangIncludeLib> calcIncludeLibs() {
    ErlangFileStub stub = getStub();
    if (stub != null) {
      return getChildrenByType(stub, ErlangTypes.ERL_INCLUDE_LIB, ErlangIncludeLibElementType.ARRAY_FACTORY);
    }

    final List<ErlangIncludeLib> result = new ArrayList<ErlangIncludeLib>();
    processChildrenDummyAware(this, new Processor<PsiElement>() {
      @Override
      public boolean process(PsiElement psiElement) {
        if (psiElement instanceof ErlangIncludeLib) {
          result.add((ErlangIncludeLib) psiElement);
        }
        return true;
      }
    });
    return result;
  }

  @NotNull
  @Override
  public List<ErlangBehaviour> getBehaviours() {
    return myBehavioursValue.getValue();
  }

  private List<ErlangBehaviour> calcBehaviours() {
    ErlangFileStub stub = getStub();
    if (stub != null) {
      return getChildrenByType(stub, ErlangTypes.ERL_BEHAVIOUR, ErlangBehaviourStubElementType.ARRAY_FACTORY);
    }

    final List<ErlangBehaviour> result = new ArrayList<ErlangBehaviour>();
    processChildrenDummyAware(this, new Processor<PsiElement>() {
      @Override
      public boolean process(PsiElement psiElement) {
        if (psiElement instanceof ErlangAttribute && ((ErlangAttribute) psiElement).getBehaviour() != null) {
          result.add(((ErlangAttribute) psiElement).getBehaviour());
        }
        return true;
      }
    });
    return result;
  }

  @NotNull
  @Override
  public List<ErlangSpecification> getSpecifications() {
    return mySpecificationsValue.getValue();
  }

  private List<ErlangSpecification> calcSpecifications() {
    final ArrayList<ErlangSpecification> result = new ArrayList<ErlangSpecification>();
    processChildrenDummyAware(this, new Processor<PsiElement>() {
      @Override
      public boolean process(PsiElement psiElement) {
        if (psiElement instanceof ErlangAttribute && ((ErlangAttribute) psiElement).getSpecification() != null) {
          result.add(((ErlangAttribute) psiElement).getSpecification());
        }
        return true;
      }
    });
    return result;
  }

  @Override
  public ErlangRecordDefinition getRecord(String name) {
    return myRecordsMap.getValue().get(name);
  }

  @NotNull
  @Override
  public ArrayList<ErlangImportFunction> getImportedFunctions() {
    ArrayList<ErlangImportFunction> result = new ArrayList<ErlangImportFunction>();
    for (ErlangAttribute attribute : getAttributes()) {
      ErlangImportDirective importDirective = attribute.getImportDirective();
      if (importDirective != null) {
        ErlangImportFunctions importFunctions = importDirective.getImportFunctions();
        if (importFunctions != null) {
          List<ErlangImportFunction> importFunctionList = importFunctions.getImportFunctionList();
          for (ErlangImportFunction importFunction : importFunctionList) {
            result.add(importFunction);
          }
        }
      }
    }
    return result;
  }

  private List<ErlangFunction> calcFunctions() {
    ErlangFileStub stub = getStub();
    if (stub != null) {
      return getChildrenByType(stub, ErlangTypes.ERL_FUNCTION, ErlangFunctionStubElementType.ARRAY_FACTORY);
    }

    final List<ErlangFunction> result = new ArrayList<ErlangFunction>();
    processChildrenDummyAware(this, new Processor<PsiElement>() {
      @Override
      public boolean process(PsiElement psiElement) {
        if (psiElement instanceof ErlangFunction) {
          result.add((ErlangFunction) psiElement);
        }
        return true;
      }
    });
    return result;
  }

  private List<ErlangAttribute> calcAttributes() {
    final List<ErlangAttribute> result = new ArrayList<ErlangAttribute>();
    processChildrenDummyAware(this, new Processor<PsiElement>() {
      @Override
      public boolean process(PsiElement psiElement) {
        if (psiElement instanceof ErlangAttribute) {
          result.add((ErlangAttribute) psiElement);
        }
        return true;
      }
    });
    return result;
  }

  private List<ErlangRule> calcRules() {
    final List<ErlangRule> result = new ArrayList<ErlangRule>();
    processChildrenDummyAware(this, new Processor<PsiElement>() {
      @Override
      public boolean process(PsiElement psiElement) {
        if (psiElement instanceof ErlangRule) {
          result.add((ErlangRule) psiElement);
        }
        return true;
      }
    });
    return result;
  }

  @Override
  public void addDeclaredParseTransforms(@NotNull Set<String> parseTransforms) {
    ErlangFileStub stub = getStub();
    if (stub != null) {
      String fromStub = stub.getParseTransforms();
      List<String> split = StringUtil.split(fromStub, ",");
      parseTransforms.addAll(split);
      return;
    }
    for (ErlangAttribute attribute : getAttributes()) {
      ErlangAtomAttribute atomAttribute = attribute.getAtomAttribute();
      ErlangQAtom qAtom = null != atomAttribute ? atomAttribute.getQAtom() : null;
      ErlangAtom atom = null != qAtom ? qAtom.getAtom() : null;
      String attributeName = null != atom ? atom.getName() : null;
      ErlangAttrVal attrVal = atomAttribute != null ? atomAttribute.getAttrVal() : null;
      if (!"compile".equals(attributeName) || attrVal == null) continue;

      for (ErlangExpression expression : attrVal.getExpressionList()) {
        //TODO support macros
        if (expression instanceof ErlangListExpression) {
          ErlangPsiImplUtil.extractParseTransforms((ErlangListExpression) expression, parseTransforms);
        }
        if (expression instanceof ErlangTupleExpression) {
          ErlangPsiImplUtil.extractParseTransforms((ErlangTupleExpression) expression, parseTransforms);
        }
      }
    }
  }

  private static boolean processChildrenDummyAware(ErlangFileImpl file, final Processor<PsiElement> processor) {
    StubTree stubTree = file.getStubTree();
    if (stubTree != null) {
      List<StubElement<?>> plainList = stubTree.getPlainList();
      for (StubElement<?> stubElement : plainList) {
        PsiElement psi = stubElement.getPsi();
        if (!processor.process(psi)) return false;
      }
      return true;
    }

    return new Processor<PsiElement>() {
      @Override
      public boolean process(PsiElement psiElement) {
        for (PsiElement child = psiElement.getFirstChild(); child != null; child = child.getNextSibling()) {
          if (child instanceof ErlangParserUtil.DummyBlock) {
            if (!process(child)) return false;
          }
          else if (!processor.process(child)) return false;
        }
        return true;
      }
    }.process(file);
  }

  @Nullable
  @Override
  public PsiElement getNameIdentifier() {
    return null; // hack for inplace rename: InplaceRefactoring#getVariable()
  }
}
TOP

Related Classes of org.intellij.erlang.psi.impl.ErlangFileImpl

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.