use of org.elixir_lang.psi.operation.Type in project intellij-elixir by KronicDeth.
the class Callback method parameterizedTypeHeadCall.
/*
* Private Static Methods
*/
@Nullable
private static Call parameterizedTypeHeadCall(ElixirMatchedWhenOperation whenOperation) {
PsiElement leftOperand = whenOperation.leftOperand();
Call headCall = null;
if (leftOperand instanceof Type) {
headCall = typeHeadCall((Type) leftOperand);
}
return headCall;
}
use of org.elixir_lang.psi.operation.Type in project intellij-elixir by KronicDeth.
the class ModuleAttribute method highlightSpecification.
/**
* Recursively highlights the types under `atUnqualifiedNoParenthesesCall`.
*
* @param atUnqualifiedNoParenthesesCall
* @param annotationHolder
* @param leftMostFunctionNameTextAttributesKey the {@link ElixirSyntaxHighlighter} {@link TextAttributesKey} for the
* name of the callback, type, or function being declared
* @param leftMostFunctionArgumentsTextAttributesKey the {@link ElixirSyntaxHighlighter} {@link TextAttributesKey} for the
* arguments of the callback, type, or function being declared
*/
private void highlightSpecification(AtUnqualifiedNoParenthesesCall atUnqualifiedNoParenthesesCall, AnnotationHolder annotationHolder, TextAttributesKey leftMostFunctionNameTextAttributesKey, TextAttributesKey leftMostFunctionArgumentsTextAttributesKey) {
PsiElement noParenthesesOneArgument = atUnqualifiedNoParenthesesCall.getNoParenthesesOneArgument();
PsiElement[] grandChildren = noParenthesesOneArgument.getChildren();
if (grandChildren.length == 1) {
PsiElement grandChild = grandChildren[0];
if (grandChild instanceof Type) {
Infix infix = (Infix) grandChild;
PsiElement leftOperand = infix.leftOperand();
if (leftOperand instanceof Call) {
Call call = (Call) leftOperand;
PsiElement functionNameElement = call.functionNameElement();
if (functionNameElement != null) {
highlight(functionNameElement.getTextRange(), annotationHolder, leftMostFunctionNameTextAttributesKey);
}
PsiElement[] primaryArguments = call.primaryArguments();
if (primaryArguments != null) {
highlightTypesAndTypeParameterUsages(primaryArguments, Collections.EMPTY_SET, annotationHolder, leftMostFunctionArgumentsTextAttributesKey);
}
PsiElement[] secondaryArguments = call.secondaryArguments();
if (secondaryArguments != null) {
highlightTypesAndTypeParameterUsages(secondaryArguments, Collections.EMPTY_SET, annotationHolder, leftMostFunctionArgumentsTextAttributesKey);
}
}
PsiElement rightOperand = infix.rightOperand();
if (rightOperand != null) {
highlightTypesAndTypeParameterUsages(rightOperand, Collections.EMPTY_SET, annotationHolder, ElixirSyntaxHighlighter.TYPE);
}
} else if (grandChild instanceof ElixirMatchedWhenOperation) {
ElixirMatchedWhenOperation matchedWhenOperation = (ElixirMatchedWhenOperation) grandChild;
Set<String> typeParameterNameSet = specificationTypeParameterNameSet(matchedWhenOperation.rightOperand());
PsiElement leftOperand = matchedWhenOperation.leftOperand();
if (leftOperand instanceof Type) {
Type typeOperation = (Type) leftOperand;
PsiElement typeOperationLeftOperand = typeOperation.leftOperand();
PsiElement strippedTypeOperationLeftOperand = null;
if (typeOperationLeftOperand != null) {
strippedTypeOperationLeftOperand = stripAllOuterParentheses(typeOperationLeftOperand);
}
if (strippedTypeOperationLeftOperand instanceof Call) {
Call call = (Call) strippedTypeOperationLeftOperand;
PsiElement functionNameElement = call.functionNameElement();
if (functionNameElement != null) {
highlight(functionNameElement.getTextRange(), annotationHolder, leftMostFunctionNameTextAttributesKey);
}
PsiElement[] primaryArguments = call.primaryArguments();
if (primaryArguments != null) {
highlightTypesAndTypeParameterUsages(primaryArguments, typeParameterNameSet, annotationHolder, leftMostFunctionArgumentsTextAttributesKey);
}
PsiElement[] secondaryArguments = call.secondaryArguments();
if (secondaryArguments != null) {
highlightTypesAndTypeParameterUsages(secondaryArguments, typeParameterNameSet, annotationHolder, leftMostFunctionArgumentsTextAttributesKey);
}
} else {
cannotHighlightTypes(strippedTypeOperationLeftOperand);
}
PsiElement matchedTypeOperationRightOperand = typeOperation.rightOperand();
if (matchedTypeOperationRightOperand != null) {
highlightTypesAndTypeParameterUsages(matchedTypeOperationRightOperand, typeParameterNameSet, annotationHolder, ElixirSyntaxHighlighter.TYPE);
}
} else {
cannotHighlightTypes(leftOperand);
}
Quotable rightOperand = matchedWhenOperation.rightOperand();
if (rightOperand != null) {
highlightTypesAndSpecificationTypeParameterDeclarations(rightOperand, typeParameterNameSet, annotationHolder, ElixirSyntaxHighlighter.TYPE);
}
}
}
}
use of org.elixir_lang.psi.operation.Type in project intellij-elixir by KronicDeth.
the class ModuleAttribute method highlightType.
/**
* Highlights the function name of the declared @type, @typep, or @opaque as an {@link ElixirSyntaxHighlighter.TYPE}
* and the its parameters as {@link ElixirSyntaxHighlighter.TYPE_PARAMETER}.
*/
private void highlightType(@NotNull final AtUnqualifiedNoParenthesesCall atUnqualifiedNoParenthesesCall, @NotNull final AnnotationHolder annotationHolder) {
PsiElement noParenthesesOneArgument = atUnqualifiedNoParenthesesCall.getNoParenthesesOneArgument();
PsiElement[] grandChildren = noParenthesesOneArgument.getChildren();
if (grandChildren.length == 1) {
PsiElement grandChild = grandChildren[0];
if (grandChild instanceof Match || /* Match is invalid. It will be marked by
MatchOperatorInsteadOfTypeOperator inspection as an error */
grandChild instanceof Type) {
Infix infix = (Infix) grandChild;
PsiElement leftOperand = infix.leftOperand();
Set<String> typeParameterNameSet = Collections.emptySet();
if (leftOperand instanceof Call) {
Call call = (Call) leftOperand;
highlightTypeName(call, annotationHolder);
if (call instanceof ElixirMatchedUnqualifiedNoArgumentsCall) {
// no arguments, so nothing else to do
} else if (call instanceof ElixirMatchedUnqualifiedParenthesesCall) {
typeParameterNameSet = highlightTypeLeftOperand((ElixirMatchedUnqualifiedParenthesesCall) call, annotationHolder);
} else {
cannotHighlightTypes(call);
}
} else {
cannotHighlightTypes(leftOperand);
}
PsiElement rightOperand = infix.rightOperand();
if (rightOperand != null) {
highlightTypesAndTypeParameterUsages(rightOperand, typeParameterNameSet, annotationHolder, ElixirSyntaxHighlighter.TYPE);
}
} else if (grandChild instanceof ElixirMatchedUnqualifiedParenthesesCall) {
// seen as `unquote(ast)`, but could also be just the beginning of typing
ElixirMatchedUnqualifiedParenthesesCall matchedUnqualifiedParenthesesCall = (ElixirMatchedUnqualifiedParenthesesCall) grandChild;
if (matchedUnqualifiedParenthesesCall.functionName().equals(UNQUOTE)) {
PsiElement[] secondaryArguments = matchedUnqualifiedParenthesesCall.secondaryArguments();
if (secondaryArguments != null) {
Set<String> typeParameterNameSet = typeTypeParameterNameSet(secondaryArguments);
highlightTypesAndTypeTypeParameterDeclarations(secondaryArguments, typeParameterNameSet, annotationHolder, ElixirSyntaxHighlighter.TYPE);
}
} else {
ElixirMatchedUnqualifiedParenthesesCall grandChildCall = (ElixirMatchedUnqualifiedParenthesesCall) grandChild;
highlightTypeName(grandChildCall, annotationHolder);
// Assume it's `@type foo(bar)` before completed as `@type foo(bar) :: bar`
highlightTypeLeftOperand((ElixirMatchedUnqualifiedParenthesesCall) grandChild, annotationHolder);
}
} else if (grandChild instanceof QuotableKeywordList) {
QuotableKeywordList quotableKeywordList = (QuotableKeywordList) grandChild;
List<QuotableKeywordPair> quotableKeywordPairList = quotableKeywordList.quotableKeywordPairList();
// occurs when user does `my_type: definition` instead of `my_type :: definition`
if (quotableKeywordPairList.size() == 1) {
QuotableKeywordPair quotableKeywordPair = quotableKeywordPairList.get(0);
Quotable quotableKeywordKey = quotableKeywordPair.getKeywordKey();
if (quotableKeywordKey instanceof ElixirKeywordKey) {
ElixirKeywordKey keywordKey = (ElixirKeywordKey) quotableKeywordKey;
highlight(keywordKey.getTextRange(), annotationHolder, ElixirSyntaxHighlighter.TYPE);
}
Quotable quotableKeywordValue = quotableKeywordPair.getKeywordValue();
highlightTypesAndTypeParameterUsages(quotableKeywordValue, Collections.<String>emptySet(), annotationHolder, ElixirSyntaxHighlighter.TYPE);
}
// Otherwise, allow the normal, non-type highlighting
} else if (grandChild instanceof UnqualifiedNoArgumentsCall) {
// assume it's a type name that is being typed
Call grandChildCall = (Call) grandChild;
PsiElement functionNameElement = grandChildCall.functionNameElement();
if (functionNameElement != null) {
highlight(functionNameElement.getTextRange(), annotationHolder, ElixirSyntaxHighlighter.TYPE);
}
} else if (grandChild instanceof UnqualifiedNoParenthesesCall) {
/* Pretend that `::` separates the functionNameElement from the arguments, so that
```
@type coefficient non_neg_integer | :qNaN | :sNaN | :inf
```
is retreated like
```
@type coefficient :: non_neg_integer | :qNaN | :sNaN | :inf
```
*/
UnqualifiedNoParenthesesCall unqualifiedNoParenthesesCall = (UnqualifiedNoParenthesesCall) grandChild;
PsiElement functionNameElement = unqualifiedNoParenthesesCall.functionNameElement();
if (functionNameElement != null) {
highlight(functionNameElement.getTextRange(), annotationHolder, ElixirSyntaxHighlighter.TYPE);
}
highlightTypesAndTypeParameterUsages(unqualifiedNoParenthesesCall.getNoParenthesesOneArgument(), Collections.<String>emptySet(), annotationHolder, ElixirSyntaxHighlighter.TYPE);
} else {
cannotHighlightTypes(grandChild);
}
}
}
use of org.elixir_lang.psi.operation.Type in project intellij-elixir by KronicDeth.
the class Builder method buildFoldRegions.
/*
* Instance Methods
*/
/**
* Builds the folding regions for the specified node in the AST tree and its children.
*
* @param root the element for which folding is requested.
* @param document the document for which folding is built. Can be used to retrieve line
* numbers for folding regions.
* @param quick whether the result should be provided as soon as possible. Is true, when
* an editor is opened and we need to auto-fold something immediately, like Java imports.
* If true, one should perform no reference resolving and avoid complex checks if possible.
* @return the array of folding descriptors.
*/
@NotNull
@Override
public FoldingDescriptor[] buildFoldRegions(@NotNull PsiElement root, @NotNull Document document, final boolean quick) {
final List<FoldingDescriptor> foldingDescriptorList = new ArrayList<FoldingDescriptor>();
PsiTreeUtil.processElements(root, new PsiElementProcessor() {
private Map<String, FoldingGroup> foldingGroupByModuleAttributeName = new HashMap<String, FoldingGroup>();
/*
*
* Instance Methods
*
*/
/*
* Public Instance Methods
*/
@Override
public boolean execute(@NotNull PsiElement element) {
boolean keepProcessing = true;
if (element instanceof AtNonNumericOperation) {
keepProcessing = execute((AtNonNumericOperation) element);
} else if (element instanceof AtUnqualifiedNoParenthesesCall) {
keepProcessing = execute((AtUnqualifiedNoParenthesesCall) element);
} else if (element instanceof ElixirDoBlock) {
keepProcessing = execute((ElixirDoBlock) element);
} else if (element instanceof ElixirStabOperation) {
keepProcessing = execute((ElixirStabOperation) element);
} else if (element instanceof Call) {
keepProcessing = execute((Call) element);
}
return keepProcessing;
}
/*
* Private Instance Methods
*/
private boolean execute(@NotNull AtNonNumericOperation atNonNumericOperation) {
boolean keepProcessing = true;
if (!quick) {
keepProcessing = slowExecute(atNonNumericOperation);
}
return keepProcessing;
}
private boolean execute(@NotNull AtUnqualifiedNoParenthesesCall atUnqualifiedNoParenthesesCall) {
String moduleAttributeName = moduleAttributeName(atUnqualifiedNoParenthesesCall);
String name = moduleAttributeName.substring(1);
if (ModuleAttribute.isDocumentationName(name)) {
ElixirNoParenthesesOneArgument noParenthesesOneArgument = atUnqualifiedNoParenthesesCall.getNoParenthesesOneArgument();
foldingDescriptorList.add(new NamedFoldingDescriptor(noParenthesesOneArgument.getNode(), noParenthesesOneArgument.getTextRange(), null, "\"...\""));
} else if (ModuleAttribute.isTypeName(name)) {
ElixirNoParenthesesOneArgument noParenthesesOneArgument = atUnqualifiedNoParenthesesCall.getNoParenthesesOneArgument();
PsiElement[] children = noParenthesesOneArgument.getChildren();
if (children.length == 1) {
PsiElement child = children[0];
if (child instanceof Type) {
Type type = (Type) child;
PsiElement rightOperand = Normalized.rightOperand(type);
if (rightOperand != null) {
foldingDescriptorList.add(new NamedFoldingDescriptor(rightOperand.getNode(), rightOperand.getTextRange(), null, "..."));
}
}
}
}
return true;
}
private boolean execute(@NotNull Call call) {
for (String resolvedFunctionName : RESOLVED_FUNCTION_NAMES) {
if (call.isCalling(KERNEL, resolvedFunctionName)) {
if (isFirstInGroup(call, KERNEL, resolvedFunctionName)) {
Call last = lastInGroup(call, KERNEL, resolvedFunctionName);
PsiElement[] finalArguments = finalArguments(call);
if (finalArguments != null && finalArguments.length >= 1) {
TextRange textRange = new TextRange(finalArguments[0].getTextOffset(), last.getTextRange().getEndOffset());
foldingDescriptorList.add(new NamedFoldingDescriptor(call.getParent().getNode(), textRange, null, "..."));
}
}
}
}
return true;
}
private boolean execute(@NotNull ElixirDoBlock doBlock) {
foldingDescriptorList.add(new FoldingDescriptor(doBlock, doBlock.getTextRange()));
return true;
}
private boolean execute(@NotNull ElixirStabOperation stabOperation) {
int startOffset = stabOperation.operator().getTextOffset();
int endOffset = stabOperation.getTextRange().getEndOffset();
TextRange textRange = new TextRange(startOffset, endOffset);
foldingDescriptorList.add(new FoldingDescriptor(stabOperation, textRange));
return true;
}
private boolean isFirstInGroup(@NotNull Call call, @NotNull String resolvedModuleName, @NotNull String resolvedFunctionName) {
PsiElement previousSiblingExpression = previousSiblingExpression(call);
boolean first = true;
if (previousSiblingExpression instanceof Call) {
Call previousSiblingExpressionCall = (Call) previousSiblingExpression;
first = !previousSiblingExpressionCall.isCalling(resolvedModuleName, resolvedFunctionName);
}
return first;
}
@NotNull
private Call lastInGroup(@NotNull Call first, @NotNull String resolvedModuleName, @NotNull String resolvedFunctionName) {
PsiElement expression = first;
Call last = first;
while (true) {
expression = nextSiblingExpression(expression);
if (expression instanceof Call) {
Call call = (Call) expression;
if (call.isCalling(resolvedModuleName, resolvedFunctionName)) {
last = call;
continue;
}
}
break;
}
return last;
}
private boolean slowExecute(@NotNull AtNonNumericOperation atNonNumericOperation) {
boolean keepProcessing = true;
PsiReference reference = atNonNumericOperation.getReference();
if (reference != null) {
keepProcessing = slowExecute(atNonNumericOperation, reference);
}
return keepProcessing;
}
private boolean slowExecute(@NotNull AtNonNumericOperation atNonNumericOperation, @NotNull final AtUnqualifiedNoParenthesesCall atUnqualifiedNoParenthesesCall) {
return slowExecute(atNonNumericOperation, atUnqualifiedNoParenthesesCall, atUnqualifiedNoParenthesesCall.getNoParenthesesOneArgument().getText());
}
private boolean slowExecute(@NotNull AtNonNumericOperation atNonNumericOperation, @NotNull PsiElement target) {
boolean keepProcessing = true;
if (target instanceof AtUnqualifiedNoParenthesesCall) {
keepProcessing = slowExecute(atNonNumericOperation, (AtUnqualifiedNoParenthesesCall) target);
} else if (target instanceof QualifiableAlias) {
keepProcessing = slowExecute(atNonNumericOperation, (QualifiableAlias) target);
}
return keepProcessing;
}
private boolean slowExecute(@NotNull AtNonNumericOperation atNonNumericOperation, @NotNull PsiReference reference) {
PsiElement target = reference.resolve();
boolean keepProcessing = true;
if (target != null) {
keepProcessing = slowExecute(atNonNumericOperation, target);
}
return keepProcessing;
}
private boolean slowExecute(@NotNull AtNonNumericOperation atNonNumericOperation, @NotNull final QualifiableAlias qualifiableAlias) {
return slowExecute(atNonNumericOperation, qualifiableAlias, qualifiableAlias.getName());
}
private boolean slowExecute(@NotNull AtNonNumericOperation atNonNumericOperation, @NotNull PsiElement element, @Nullable final String placeHolderText) {
String moduleAttributeName = atNonNumericOperation.moduleAttributeName();
FoldingGroup foldingGroup = foldingGroupByModuleAttributeName.get(moduleAttributeName);
if (foldingGroup == null) {
foldingGroup = FoldingGroup.newGroup(moduleAttributeName);
foldingGroupByModuleAttributeName.put(moduleAttributeName, foldingGroup);
}
foldingDescriptorList.add(new FoldingDescriptor(atNonNumericOperation.getNode(), atNonNumericOperation.getTextRange(), foldingGroup, Collections.<Object>singleton(element)) {
@Nullable
@Override
public String getPlaceholderText() {
return placeHolderText;
}
});
return true;
}
});
return foldingDescriptorList.toArray(new FoldingDescriptor[foldingDescriptorList.size()]);
}
use of org.elixir_lang.psi.operation.Type in project intellij-elixir by KronicDeth.
the class ElixirPsiImplUtil method getReference.
@Nullable
public static PsiReference getReference(@NotNull Call call) {
PsiReference reference = null;
/* if the call is just the identifier for a module attribute reference, then don't return a Callable reference,
and instead let {@link #getReference(AtNonNumbericOperation) handle it */
if (!(call instanceof UnqualifiedNoArgumentsCall && call.getParent() instanceof AtNonNumericOperation) && // if a bitstring segment option then the option is a pseudo-function
!isBitStreamSegmentOption(call)) {
PsiElement parent = call.getParent();
if (parent instanceof Type) {
PsiElement grandParent = parent.getParent();
AtUnqualifiedNoParenthesesCall moduleAttribute = null;
PsiElement maybeArgument = grandParent;
if (grandParent instanceof When) {
maybeArgument = grandParent.getParent();
}
if (maybeArgument instanceof ElixirNoParenthesesOneArgument) {
PsiElement maybeModuleAttribute = maybeArgument.getParent();
if (maybeModuleAttribute instanceof AtUnqualifiedNoParenthesesCall) {
moduleAttribute = (AtUnqualifiedNoParenthesesCall) maybeModuleAttribute;
}
if (moduleAttribute != null) {
String name = moduleAttributeName(moduleAttribute);
if (name.equals("@spec")) {
reference = new org.elixir_lang.reference.CallDefinitionClause(call, moduleAttribute);
}
}
}
}
if (reference == null) {
if (CallDefinitionClause.is(call) || Implementation.is(call) || Module.is(call) || Protocol.is(call)) {
reference = Callable.definer(call);
} else {
reference = new Callable(call);
}
}
}
return reference;
}
Aggregations