// Copyright 2014 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).
package com.twitter.intellij.pants.util;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.psi.PyArgumentList;
import com.jetbrains.python.psi.PyCallExpression;
import com.jetbrains.python.psi.PyDictLiteralExpression;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyExpressionStatement;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyFunction;
import com.jetbrains.python.psi.PyKeyValueExpression;
import com.jetbrains.python.psi.PyKeywordArgument;
import com.jetbrains.python.psi.PyReferenceExpression;
import com.jetbrains.python.psi.PyReturnStatement;
import com.jetbrains.python.psi.PyStatement;
import com.jetbrains.python.psi.PyStringLiteralExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import static com.intellij.openapi.util.text.StringUtil.unquoteString;
public class PantsPsiUtil {
@NotNull
public static Map<String, PyCallExpression> findTargets(@Nullable PsiFile file) {
if (file == null) {
return Collections.emptyMap();
}
final Map<String, PyCallExpression> result = new HashMap<String, PyCallExpression>();
for (PyExpressionStatement statement : PsiTreeUtil.findChildrenOfType(file, PyExpressionStatement.class)) {
final Pair<String, PyCallExpression> nameExpressionPair = findTarget(statement);
if (nameExpressionPair != null) {
result.put(nameExpressionPair.getFirst(), nameExpressionPair.getSecond());
}
}
return result;
}
@Nullable
public static Pair<String, PyCallExpression> findTarget(@NotNull PyExpressionStatement statement) {
final PyCallExpression expression = PsiTreeUtil.findChildOfType(statement, PyCallExpression.class);
final PyExpression callee = expression != null ? expression.getCallee() : null;
final PyArgumentList argumentList = expression != null ? expression.getArgumentList() : null;
final PyKeywordArgument nameArgument = argumentList != null ? argumentList.getKeywordArgument("name") : null;
final PyExpression valueExpression = nameArgument != null ? nameArgument.getValueExpression() : null;
if (valueExpression != null && callee != null) {
return Pair.create(unquoteString(valueExpression.getText()), expression);
}
return null;
}
@NotNull
public static Map<String, PyReferenceExpression> findTargetDefinitions(@NotNull PyFile pyFile) {
final PyFunction buildFileAliases = pyFile.findTopLevelFunction("build_file_aliases");
final PyStatement[] statements =
buildFileAliases != null ? buildFileAliases.getStatementList().getStatements() : PyStatement.EMPTY_ARRAY;
final Map<String, PyReferenceExpression> result = new HashMap<String, PyReferenceExpression>();
for (PyStatement statement : statements) {
if (!(statement instanceof PyReturnStatement)) {
continue;
}
final PyExpression returnExpression = ((PyReturnStatement)statement).getExpression();
if (!(returnExpression instanceof PyCallExpression)) {
continue;
}
final PyArgumentList argumentList = ((PyCallExpression)returnExpression).getArgumentList();
final Collection<PyKeywordArgument> targetDefinitions = PsiTreeUtil.findChildrenOfType(argumentList, PyKeywordArgument.class);
for (PyKeywordArgument targets : targetDefinitions) {
final PyExpression targetsExpression = targets != null ? targets.getValueExpression() : null;
if (targetsExpression instanceof PyDictLiteralExpression) {
for (PyKeyValueExpression keyValueExpression : ((PyDictLiteralExpression)targetsExpression).getElements()) {
final PyExpression keyExpression = keyValueExpression.getKey();
final PyExpression valueExpression = keyValueExpression.getValue();
if (keyExpression instanceof PyStringLiteralExpression) {
result.put(
((PyStringLiteralExpression)keyExpression).getStringValue(),
valueExpression instanceof PyReferenceExpression ? (PyReferenceExpression)valueExpression : null
);
}
}
}
}
}
return result;
}
}