package org.elixir_lang.psi.stub.type.call; import com.intellij.lang.ASTNode; import com.intellij.psi.stubs.StubInputStream; import com.intellij.psi.stubs.StubOutputStream; import com.intellij.util.containers.SmartHashSet; import com.intellij.util.io.StringRef; import org.elixir_lang.psi.call.Call; import org.elixir_lang.psi.call.StubBased; import org.elixir_lang.psi.stub.call.Stubbic; import org.elixir_lang.structure_view.element.*; import org.elixir_lang.structure_view.element.modular.Implementation; import org.elixir_lang.structure_view.element.modular.Module; import org.elixir_lang.structure_view.element.modular.Protocol; import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.util.Collection; import java.util.Set; public abstract class Stub<Stub extends org.elixir_lang.psi.stub.call.Stub<Psi>, Psi extends org.elixir_lang.psi.call.StubBased> extends org.elixir_lang.psi.stub.type.Named<Stub, Psi> { /* * Static Methods */ public static boolean isModular(Call call) { return Implementation.is(call) || Module.is(call) || Protocol.is(call); } public static Set<StringRef> readNameSet(@NotNull StubInputStream dataStream) throws IOException { int nameSetSize = dataStream.readInt(); Set<StringRef> nameSet = new SmartHashSet<StringRef>(nameSetSize); for (int i = 0; i < nameSetSize; i++) { nameSet.add(dataStream.readName()); } return nameSet; } public static <T extends Stubbic> void serializeStubbic(@NotNull T stub, @NotNull StubOutputStream dataStream) throws IOException { dataStream.writeName(stub.resolvedModuleName()); dataStream.writeName(stub.resolvedFunctionName()); dataStream.writeInt(stub.resolvedFinalArity()); dataStream.writeBoolean(stub.hasDoBlockOrKeyword()); dataStream.writeName(stub.getName()); writeNameSet(dataStream, stub.canonicalNameSet()); } /* * Private Static Methods */ private static void writeNameSet(@NotNull StubOutputStream dataStream, @NotNull Collection<String> nameCollection) throws IOException { dataStream.writeInt(nameCollection.size()); for (String name : nameCollection) { dataStream.writeName(name); } } /* * Constructors */ public Stub(@NotNull String debugName) { super(debugName); } /* * Instance Methods */ @Override public void serialize(@NotNull Stub stub, @NotNull StubOutputStream dataStream) throws IOException { serializeStubbic(stub, dataStream); } @Override public boolean shouldCreateStub(ASTNode node) { Call call = (Call) node.getPsi(); return isNameable(call) && hasNameOrCanonicalNames(call); } /* * Private Instance Methods */ private boolean hasCanonicalNames(Call call) { boolean hasCanonicalNames = false; if (call instanceof StubBased) { StubBased stubBased = (StubBased) call; hasCanonicalNames = stubBased.canonicalNameSet().size() > 0; } return hasCanonicalNames; } private boolean hasName(Call call) { return call.getName() != null; } private boolean hasNameOrCanonicalNames(Call call) { return hasName(call) || hasCanonicalNames(call); } private boolean isDelegationCallDefinitionHead(Call call) { return CallDefinitionHead.is(call) && CallDefinitionHead.enclosingDelegationCall(call) != null; } private boolean isEnclosableByModular(Call call) { return CallDefinitionClause.is(call) || /* skip CallDefinitionHead because there can be false positives the the ancestor calls need to be checked */ CallDefinitionSpecification.is(call) || // skip CallDefinitionHead because it is covered by CallDefinitionClause Callback.is(call); } private boolean isNameable(Call call) { return isEnclosableByModular(call) || isDelegationCallDefinitionHead(call) || isModular(call); } }