Skip to content

Instantly share code, notes, and snippets.

@kingsleyadio
Created April 20, 2018 07:29
Show Gist options
  • Save kingsleyadio/2f1600aaff220916dc2f00ab8464638e to your computer and use it in GitHub Desktop.
Save kingsleyadio/2f1600aaff220916dc2f00ab8464638e to your computer and use it in GitHub Desktop.
Enhanced structural search and replace script in IJ/AS using PSI based groovy code snippet
// $symbol$ => defines a matcher for the identifier being replaced
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl as ReferenceExpression
import com.intellij.psi.impl.source.tree.java.PsiLocalVariableImpl as LocalVariable
import com.intellij.psi.impl.source.PsiFieldImpl as Field
symbol instanceof Field || symbol instanceof ReferenceExpression || symbol instanceof LocalVariable
// $updatedSymbol$ => defines the transformation logic for the replacing text
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl as ReferenceExpression
import com.intellij.psi.impl.source.tree.java.PsiExpressionStatementImpl as ExpressionStatement
import com.intellij.psi.impl.source.tree.java.PsiDeclarationStatementImpl as DeclarationStatement
import com.intellij.psi.impl.source.tree.java.PsiAssignmentExpressionImpl as AssignmentExpression
def name = (symbol instanceof ReferenceExpression) ? symbol.referenceName : symbol.name
if (name == null || name == "mView") {
// Intentionally leave out `mView`. This could also have been applied in initial $symbol$ matcher
return name
}
def expectedName = name[1].toLowerCase() + name.substring(2)
def parent = symbol.parent
while (parent != null && !(parent instanceof ExpressionStatement) && !(parent instanceof DeclarationStatement)) {
parent = parent.parent
}
if (parent != null && parent.text.contains(expectedName)) {
expectedName = "this." + expectedName
}
return expectedName
@kingsleyadio
Copy link
Author

Note however, the replace logic is a very basic procedure, so one should endeavour to verify that the process passed as expected, and there are no surprises.
Potential improvement could take more advantage of context. The snippet below for example, would fail with the current logic:

void setList(List<SomeClass> list) {
  mList.clear(); // this line alone does not provide enough context, resulting in a semantically wrong `list.clear()`
  mList = list; // this line will be correctly transformed to `this.list = list`
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment