diff --git a/smalidea/META-INF/plugin.xml b/smalidea/META-INF/plugin.xml
index d14d8cc9..866056a4 100644
--- a/smalidea/META-INF/plugin.xml
+++ b/smalidea/META-INF/plugin.xml
@@ -19,6 +19,7 @@
+
diff --git a/smalidea/src/main/java/org/jf/smalidea/SmaliASTFactory.java b/smalidea/src/main/java/org/jf/smalidea/SmaliASTFactory.java
new file mode 100644
index 00000000..4e0208c2
--- /dev/null
+++ b/smalidea/src/main/java/org/jf/smalidea/SmaliASTFactory.java
@@ -0,0 +1,19 @@
+package org.jf.smalidea;
+
+import com.intellij.lang.ASTFactory;
+import com.intellij.psi.impl.source.tree.LeafElement;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.Nullable;
+import org.jf.smalidea.psi.leaf.SmaliClassDescriptor;
+
+public class SmaliASTFactory extends ASTFactory {
+
+ @Nullable
+ @Override
+ public LeafElement createLeaf(IElementType type, CharSequence text) {
+ if (type == SmaliTokens.CLASS_DESCRIPTOR) {
+ return new SmaliClassDescriptor(text);
+ }
+ return super.createLeaf(type, text);
+ }
+}
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java
index ea9e89d1..bd731d3f 100644
--- a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClass.java
@@ -53,6 +53,7 @@ import org.jetbrains.annotations.Nullable;
import org.jf.smalidea.SmaliIcons;
import org.jf.smalidea.psi.SmaliElementTypes;
import org.jf.smalidea.psi.iface.SmaliModifierListOwner;
+import org.jf.smalidea.psi.leaf.SmaliClassDescriptor;
import org.jf.smalidea.psi.stub.SmaliClassStub;
import javax.annotation.Nonnull;
@@ -244,8 +245,16 @@ public class SmaliClass extends SmaliStubBasedPsiElement impleme
return null;
}
- @Nullable @Override public PsiIdentifier getNameIdentifier() {
- return null;
+ @Nullable public SmaliClassStatement getClassStatement() {
+ return getStubOrPsiChild(SmaliElementTypes.CLASS_STATEMENT);
+ }
+
+ @Nullable @Override public SmaliClassDescriptor getNameIdentifier() {
+ SmaliClassStatement classStatement = getClassStatement();
+ if (classStatement == null) {
+ return null;
+ }
+ return classStatement.getNameIdentifier();
}
@Override public PsiElement getScope() {
@@ -269,7 +278,52 @@ public class SmaliClass extends SmaliStubBasedPsiElement impleme
}
@Override public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
- return null;
+ SmaliClassStatement classStatement = getClassStatement();
+ if (classStatement == null) {
+ throw new IncorrectOperationException();
+ }
+
+ SmaliClassTypeElement classTypeElement = classStatement.getNameElement();
+ if (classTypeElement == null) {
+ throw new IncorrectOperationException();
+ }
+
+ String expectedPath = "/" + getName() + ".smali";
+ String actualPath = this.getContainingFile().getVirtualFile().getPath();
+ if (actualPath.endsWith(expectedPath)) {
+ getContainingFile().setName(name + ".smali");
+ }
+
+ String packageName = this.getPackageName();
+ String newName;
+ if (packageName.length() > 0) {
+ newName = packageName + "." + name;
+ } else {
+ newName = name;
+ }
+ classTypeElement.handleElementRename(newName);
+ return this;
+ }
+
+ public void setPackageName(@NonNls @NotNull String packageName) {
+ SmaliClassStatement classStatement = getClassStatement();
+ if (classStatement == null) {
+ throw new IncorrectOperationException();
+ }
+
+ SmaliClassTypeElement classTypeElement = classStatement.getNameElement();
+ if (classTypeElement == null) {
+ throw new IncorrectOperationException();
+ }
+
+ String newName;
+ if (packageName.length() > 0) {
+ newName = packageName + "." + getName();
+ } else {
+ newName = getName();
+ }
+
+ classTypeElement.handleElementRename(newName);
}
@Nullable @Override public PsiDocComment getDocComment() {
diff --git a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassStatement.java b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassStatement.java
index 73cdf8de..65ccead6 100644
--- a/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassStatement.java
+++ b/smalidea/src/main/java/org/jf/smalidea/psi/impl/SmaliClassStatement.java
@@ -35,6 +35,7 @@ import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jf.smalidea.psi.SmaliElementTypes;
+import org.jf.smalidea.psi.leaf.SmaliClassDescriptor;
import org.jf.smalidea.psi.stub.SmaliClassStatementStub;
public class SmaliClassStatement extends SmaliStubBasedPsiElement {
@@ -46,6 +47,20 @@ public class SmaliClassStatement extends SmaliStubBasedPsiElement contentSourceRoots =
+ JavaProjectRootsUtil.getSuitableDestinationSourceRoots(getProject());
+
+ new MoveClassesOrPackagesProcessor(getProject(), new PsiClass[] {testClass},
+ new AutocreatingSingleSourceRootMoveDestination(new PackageWrapper(getPsiManager(), newPackage),
+ contentSourceRoots.get(0)), false, false, null).run();
+
+ /*new WriteCommandAction.Simple(getProject(), testClass.getContainingFile()) {
+ @Override protected void run() throws Throwable {
+
+
+ MoveClassesOrPackagesUtil.doMoveClass(testClass, newDirectory);
+ }
+ }.execute();*/
+ }
+
+}
diff --git a/smalidea/src/test/java/org/jf/smalidea/ClassRenameTest.java b/smalidea/src/test/java/org/jf/smalidea/ClassRenameTest.java
new file mode 100644
index 00000000..d1c7365b
--- /dev/null
+++ b/smalidea/src/test/java/org/jf/smalidea/ClassRenameTest.java
@@ -0,0 +1,51 @@
+package org.jf.smalidea;
+
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.refactoring.MultiFileTestCase;
+import com.intellij.refactoring.rename.RenameProcessor;
+import org.jetbrains.annotations.NotNull;
+
+public class ClassRenameTest extends MultiFileTestCase {
+ @Override
+ protected String getTestDataPath() {
+ return "testData";
+ }
+
+ @NotNull
+ @Override
+ protected String getTestRoot() {
+ return "/classRename/";
+ }
+
+ public void testBasicNoPackage() {
+ doTest("blah", "blah2");
+ }
+
+ public void testBasicWithPackage() {
+ doTest("my.blah", "blah2");
+ }
+
+ private void doTest(@NotNull final String oldQualifiedName, @NotNull final String newName) {
+ doTest(new PerformAction() {
+ @Override
+ public void performAction(VirtualFile rootDir, VirtualFile rootAfter) throws Exception {
+ doRename(oldQualifiedName, newName);
+ }
+ });
+ }
+
+ private void doRename(String oldQualifiedName, String newName) throws Exception {
+ PsiClass testClass = myJavaFacade.findClass(oldQualifiedName, GlobalSearchScope.allScope(getProject()));
+
+ RenameProcessor processor = new RenameProcessor(getProject(), testClass, newName, false, false);
+ processor.run();
+
+ PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+ FileDocumentManager.getInstance().saveAllDocuments();
+ }
+
+}
diff --git a/smalidea/testData/classMove/basicFromNoPackage/after/my/blah.smali b/smalidea/testData/classMove/basicFromNoPackage/after/my/blah.smali
new file mode 100644
index 00000000..dc4522cc
--- /dev/null
+++ b/smalidea/testData/classMove/basicFromNoPackage/after/my/blah.smali
@@ -0,0 +1,36 @@
+.class public Lmy/blah;
+.super Lmy/blah;
+.implements Lmy/blah;
+
+.annotation build Lmy/blah;
+ value = .subannotation Lmy/blah;
+ value = Lmy/blah;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lmy/blah; = Lmy/blah;
+
+.method public blah(Lmy/blah;)Lmy/blah;
+ .registers 2
+ .local p0, "this":Lmy/blah;
+
+ :start
+ iget-object v0, v0, Lmy/blah;->blah:Lmy/blah;
+
+ invoke-virtual {v0}, Lmy/blah;->blah(Lmy/blah;)Lmy/blah;
+
+ instance-of v0, v0, Lmy/blah;
+ check-cast v0, Lmy/blah;
+ new-instance v0, Lmy/blah;
+ const-class v0, Lmy/blah;
+ throw-verification-error generic-error, Lmy/blah;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lmy/blah;
+ new-array v0, v0, Lmy/blah;
+ filled-new-array/range {v0}, Lmy/blah;
+ :end
+
+ .catch Lmy/blah; { :start .. :end } :handler
+ :handler
+ return-void
+.end method
\ No newline at end of file
diff --git a/smalidea/testData/classMove/basicFromNoPackage/before/blah.smali b/smalidea/testData/classMove/basicFromNoPackage/before/blah.smali
new file mode 100644
index 00000000..0a72c715
--- /dev/null
+++ b/smalidea/testData/classMove/basicFromNoPackage/before/blah.smali
@@ -0,0 +1,36 @@
+.class public Lblah;
+.super Lblah;
+.implements Lblah;
+
+.annotation build Lblah;
+ value = .subannotation Lblah;
+ value = Lblah;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lblah; = Lblah;
+
+.method public blah(Lblah;)Lblah;
+ .registers 2
+ .local p0, "this":Lblah;
+
+ :start
+ iget-object v0, v0, Lblah;->blah:Lblah;
+
+ invoke-virtual {v0}, Lblah;->blah(Lblah;)Lblah;
+
+ instance-of v0, v0, Lblah;
+ check-cast v0, Lblah;
+ new-instance v0, Lblah;
+ const-class v0, Lblah;
+ throw-verification-error generic-error, Lblah;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lblah;
+ new-array v0, v0, Lblah;
+ filled-new-array/range {v0}, Lblah;
+ :end
+
+ .catch Lblah; { :start .. :end } :handler
+ :handler
+ return-void
+.end method
\ No newline at end of file
diff --git a/smalidea/testData/classMove/basicToNoPackage/after/blah.smali b/smalidea/testData/classMove/basicToNoPackage/after/blah.smali
new file mode 100644
index 00000000..0a72c715
--- /dev/null
+++ b/smalidea/testData/classMove/basicToNoPackage/after/blah.smali
@@ -0,0 +1,36 @@
+.class public Lblah;
+.super Lblah;
+.implements Lblah;
+
+.annotation build Lblah;
+ value = .subannotation Lblah;
+ value = Lblah;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lblah; = Lblah;
+
+.method public blah(Lblah;)Lblah;
+ .registers 2
+ .local p0, "this":Lblah;
+
+ :start
+ iget-object v0, v0, Lblah;->blah:Lblah;
+
+ invoke-virtual {v0}, Lblah;->blah(Lblah;)Lblah;
+
+ instance-of v0, v0, Lblah;
+ check-cast v0, Lblah;
+ new-instance v0, Lblah;
+ const-class v0, Lblah;
+ throw-verification-error generic-error, Lblah;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lblah;
+ new-array v0, v0, Lblah;
+ filled-new-array/range {v0}, Lblah;
+ :end
+
+ .catch Lblah; { :start .. :end } :handler
+ :handler
+ return-void
+.end method
\ No newline at end of file
diff --git a/smalidea/testData/classMove/basicToNoPackage/before/my/blah.smali b/smalidea/testData/classMove/basicToNoPackage/before/my/blah.smali
new file mode 100644
index 00000000..dc4522cc
--- /dev/null
+++ b/smalidea/testData/classMove/basicToNoPackage/before/my/blah.smali
@@ -0,0 +1,36 @@
+.class public Lmy/blah;
+.super Lmy/blah;
+.implements Lmy/blah;
+
+.annotation build Lmy/blah;
+ value = .subannotation Lmy/blah;
+ value = Lmy/blah;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lmy/blah; = Lmy/blah;
+
+.method public blah(Lmy/blah;)Lmy/blah;
+ .registers 2
+ .local p0, "this":Lmy/blah;
+
+ :start
+ iget-object v0, v0, Lmy/blah;->blah:Lmy/blah;
+
+ invoke-virtual {v0}, Lmy/blah;->blah(Lmy/blah;)Lmy/blah;
+
+ instance-of v0, v0, Lmy/blah;
+ check-cast v0, Lmy/blah;
+ new-instance v0, Lmy/blah;
+ const-class v0, Lmy/blah;
+ throw-verification-error generic-error, Lmy/blah;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lmy/blah;
+ new-array v0, v0, Lmy/blah;
+ filled-new-array/range {v0}, Lmy/blah;
+ :end
+
+ .catch Lmy/blah; { :start .. :end } :handler
+ :handler
+ return-void
+.end method
\ No newline at end of file
diff --git a/smalidea/testData/classRename/basicNoPackage/after/blah2.smali b/smalidea/testData/classRename/basicNoPackage/after/blah2.smali
new file mode 100644
index 00000000..112b106e
--- /dev/null
+++ b/smalidea/testData/classRename/basicNoPackage/after/blah2.smali
@@ -0,0 +1,36 @@
+.class public Lblah2;
+.super Lblah2;
+.implements Lblah2;
+
+.annotation build Lblah2;
+ value = .subannotation Lblah2;
+ value = Lblah2;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lblah2; = Lblah2;
+
+.method public blah(Lblah2;)Lblah2;
+ .registers 2
+ .local p0, "this":Lblah2;
+
+ :start
+ iget-object v0, v0, Lblah2;->blah:Lblah2;
+
+ invoke-virtual {v0}, Lblah2;->blah(Lblah2;)Lblah2;
+
+ instance-of v0, v0, Lblah2;
+ check-cast v0, Lblah2;
+ new-instance v0, Lblah2;
+ const-class v0, Lblah2;
+ throw-verification-error generic-error, Lblah2;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lblah2;
+ new-array v0, v0, Lblah2;
+ filled-new-array/range {v0}, Lblah2;
+ :end
+
+ .catch Lblah2; { :start .. :end } :handler
+ :handler
+ return-void
+.end method
\ No newline at end of file
diff --git a/smalidea/testData/classRename/basicNoPackage/before/blah.smali b/smalidea/testData/classRename/basicNoPackage/before/blah.smali
new file mode 100644
index 00000000..0a72c715
--- /dev/null
+++ b/smalidea/testData/classRename/basicNoPackage/before/blah.smali
@@ -0,0 +1,36 @@
+.class public Lblah;
+.super Lblah;
+.implements Lblah;
+
+.annotation build Lblah;
+ value = .subannotation Lblah;
+ value = Lblah;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lblah; = Lblah;
+
+.method public blah(Lblah;)Lblah;
+ .registers 2
+ .local p0, "this":Lblah;
+
+ :start
+ iget-object v0, v0, Lblah;->blah:Lblah;
+
+ invoke-virtual {v0}, Lblah;->blah(Lblah;)Lblah;
+
+ instance-of v0, v0, Lblah;
+ check-cast v0, Lblah;
+ new-instance v0, Lblah;
+ const-class v0, Lblah;
+ throw-verification-error generic-error, Lblah;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lblah;
+ new-array v0, v0, Lblah;
+ filled-new-array/range {v0}, Lblah;
+ :end
+
+ .catch Lblah; { :start .. :end } :handler
+ :handler
+ return-void
+.end method
\ No newline at end of file
diff --git a/smalidea/testData/classRename/basicWithPackage/after/my/blah2.smali b/smalidea/testData/classRename/basicWithPackage/after/my/blah2.smali
new file mode 100644
index 00000000..f08d5137
--- /dev/null
+++ b/smalidea/testData/classRename/basicWithPackage/after/my/blah2.smali
@@ -0,0 +1,36 @@
+.class public Lmy/blah2;
+.super Lmy/blah2;
+.implements Lmy/blah2;
+
+.annotation build Lmy/blah2;
+ value = .subannotation Lmy/blah2;
+ value = Lmy/blah2;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lmy/blah2; = Lmy/blah2;
+
+.method public blah(Lmy/blah2;)Lmy/blah2;
+ .registers 2
+ .local p0, "this":Lmy/blah2;
+
+ :start
+ iget-object v0, v0, Lmy/blah2;->blah:Lmy/blah2;
+
+ invoke-virtual {v0}, Lmy/blah2;->blah(Lmy/blah2;)Lmy/blah2;
+
+ instance-of v0, v0, Lmy/blah2;
+ check-cast v0, Lmy/blah2;
+ new-instance v0, Lmy/blah2;
+ const-class v0, Lmy/blah2;
+ throw-verification-error generic-error, Lmy/blah2;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lmy/blah2;
+ new-array v0, v0, Lmy/blah2;
+ filled-new-array/range {v0}, Lmy/blah2;
+ :end
+
+ .catch Lmy/blah2; { :start .. :end } :handler
+ :handler
+ return-void
+.end method
\ No newline at end of file
diff --git a/smalidea/testData/classRename/basicWithPackage/before/my/blah.smali b/smalidea/testData/classRename/basicWithPackage/before/my/blah.smali
new file mode 100644
index 00000000..dc4522cc
--- /dev/null
+++ b/smalidea/testData/classRename/basicWithPackage/before/my/blah.smali
@@ -0,0 +1,36 @@
+.class public Lmy/blah;
+.super Lmy/blah;
+.implements Lmy/blah;
+
+.annotation build Lmy/blah;
+ value = .subannotation Lmy/blah;
+ value = Lmy/blah;
+ .end subannotation
+.end annotation
+
+.field static public blah:Lmy/blah; = Lmy/blah;
+
+.method public blah(Lmy/blah;)Lmy/blah;
+ .registers 2
+ .local p0, "this":Lmy/blah;
+
+ :start
+ iget-object v0, v0, Lmy/blah;->blah:Lmy/blah;
+
+ invoke-virtual {v0}, Lmy/blah;->blah(Lmy/blah;)Lmy/blah;
+
+ instance-of v0, v0, Lmy/blah;
+ check-cast v0, Lmy/blah;
+ new-instance v0, Lmy/blah;
+ const-class v0, Lmy/blah;
+ throw-verification-error generic-error, Lmy/blah;
+
+ filled-new-array {v0, v0, v0, v0, v0}, Lmy/blah;
+ new-array v0, v0, Lmy/blah;
+ filled-new-array/range {v0}, Lmy/blah;
+ :end
+
+ .catch Lmy/blah; { :start .. :end } :handler
+ :handler
+ return-void
+.end method
\ No newline at end of file