Parsing PsiField with chained methods

Hi,

I have following Java field:

public static final PropertyDefinition PROPERTY_DEFAULT_VALUE_1000 = PropertyManager
.newEntityPropertyDefinition("property.DefaultValue.1000", "Default value in Integer 1000", EntityNames.PRODUCT_ALT_UOM_ENTITY)
.type(Type.TYPE_INT)
.defaultValue(new Integer(1000));

In my plugin I would like to parse initializer for methods and their argument list (method names and their argument values). Current code is not very effective and also there is problem with argument of last method.

fieldDef is PsiField

this.identifiers = findAllChildren(fieldDef, PsiIdentifier.class);

 

private static PsiElement[] findAllChildren(PsiElement element, Class<? extends PsiElement> childrenType) {
List<PsiElement> result = new ArrayList<>();
findAllChildrenRecursively(element, childrenType, result);
return result.toArray(new PsiElement[result.size()]);
}


private static void findAllChildrenRecursively(PsiElement element, Class<? extends PsiElement> childrenType, List<PsiElement> result) {
PsiElement[] children = element.getChildren();
for (PsiElement child : children) {
if (childrenType.isAssignableFrom(child.getClass())) {
result.add(child);
}
findAllChildrenRecursively(child, childrenType, result);
}
}

Is there any simpler way to do it? 

Thank you.

 

0
7 comments

Hi,

There are utility methods for this e.g. com.intellij.psi.util.PsiTreeUtil#findChildrenOfType. 

Anna

0

Awesome, I love when technical people from Jetbrains are responding even so quick. I have tried 

PsiTreeUtil.findChildrenOfType(fieldDefinition, PsiExpression.class);

this one is best opposite PsiIdentifier, PsiMethod etc. Also tried combine them but at the end I ended with somehow lagging code

private void setPropertyCommonFields() {
List<String> literalList = new ArrayList<>();
for (PsiExpression expression : this.expressionList) {
String expressionValue = getPsiElementValue(expression);
if (expressionValue.startsWith(PROPERTY_MANAGER_CLASS)) {
continue;
}
if (expression instanceof PsiReferenceExpression && expressionValue.startsWith(PROPERTY_TYPE_KEYWORD + ".")) {
setValueType(expressionValue);
}
if (expression instanceof PsiReferenceExpression && expressionValue.startsWith(PROPERTY_ENTITYNAMES_KEYWORD +".")) {
this.entityNames.add(expressionValue.replace(PROPERTY_ENTITYNAMES_KEYWORD + ".", ""));
}
// Boolean Class is not literal expression
if (expression instanceof PsiReferenceExpression &&
expressionValue.startsWith("Boolean.") || expressionValue.startsWith("Integer.") ||
expressionValue.startsWith("Double.")) {
setDefaultValue(evaluateExpression(expressionValue));
}
if (expression instanceof PsiLiteralExpression) {
if (expression.getPrevSibling() != null &&
"PsiJavaToken:MINUS".equals(expression.getPrevSibling().toString())) {
expressionValue = "-" + expressionValue;
}
literalList.add(expressionValue);
}
}
setName(literalList.get(0));
setLabel(literalList.get(1));
// default value is defined and it's literal
if (literalList.size() > 2) {
setDefaultValue(evaluateExpression(literalList.get(2)));
}
}

It's working but there has to be better way. Task seems to be easy - get chained method call after constructor and its arguments, e.g "type - Type.Type_INT", "defaultValue - new Integer(-1)" etc.

 

0

I'd rather use recursive visitor for the task com.intellij.psi.JavaRecursiveElementWalkingVisitor, visit methodCalls and their arguments. I am not sure what you try to do with the code above, though as well as you compute expressionValue. So what is the end task you try to solve?

Thanks,

Anna

0

This is field definition (there can be more method chained after method/constructor newEntityPropertyDefinition)

public static final PropertyDefinition PROPERTY_DEFAULT_VALUE_1000 = PropertyManager
.newEntityPropertyDefinition("property.DefaultValue.1000", "Default value in Integer 1000", EntityNames.PRODUCT_ALT_UOM_ENTITY)
.type(Type.TYPE_INT)
.defaultValue(new Integer(1000));

and I want to parse it to pairs (strings):

<method> - <argument value_list_(in_string_type)>

in this case

"newEntityPropertyDefinition" - {"property.DefaultValue.1000", "Default value in Integer 1000", EntityNames.PRODUCT_ALT_UOM_ENTITY"},
"type" -  {"Type.TYPE_INT"},
"defaultValue" - {"new Integer(1000)"}

Example code would be wonderful :)

Thank you.

 

 

 

 

 

 

 

0

The code you have looks much more complicated. I suggest to override com.intellij.psi.JavaElementVisitor#visitMethodCallExpression, don't forget to call super though. You can get method name and call.getArgumentList() would contain args

0

Thank you, I will try. Posted code contains also setter methods of my plugin class PropertyDefinition and some value parsing but that can be separated once I have parsed simple structure.  

0

I am looking exactly for the same. I want to parse values passed to the constructor of a class to a varaible.

 

@Znevrly, can you please share your code on how you achived it?

0

Please sign in to leave a comment.