diff --git a/hu.elte.refjava.control/.classpath b/hu.elte.refjava.control/.classpath
index e784782..428337e 100644
--- a/hu.elte.refjava.control/.classpath
+++ b/hu.elte.refjava.control/.classpath
@@ -1,10 +1,6 @@
-
-
-
-
-
+
diff --git a/hu.elte.refjava.control/.settings/org.eclipse.jdt.core.prefs b/hu.elte.refjava.control/.settings/org.eclipse.jdt.core.prefs
index 0c68a61..01b2219 100644
--- a/hu.elte.refjava.control/.settings/org.eclipse.jdt.core.prefs
+++ b/hu.elte.refjava.control/.settings/org.eclipse.jdt.core.prefs
@@ -3,5 +3,8 @@ org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=1.8
diff --git a/hu.elte.refjava.control/META-INF/MANIFEST.MF b/hu.elte.refjava.control/META-INF/MANIFEST.MF
index 4db3b9e..885f6c4 100644
--- a/hu.elte.refjava.control/META-INF/MANIFEST.MF
+++ b/hu.elte.refjava.control/META-INF/MANIFEST.MF
@@ -17,4 +17,8 @@ Require-Bundle: org.eclipse.ui,
org.eclipse.xtext.ui;bundle-version="2.15.0",
hu.elte.refjava;bundle-version="1.0.0"
Automatic-Module-Name: hu.elte.refjava.control
-Bundle-RequiredExecutionEnvironment: JavaSE-10
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Export-Package: hu.elte.refjava.control.handlers,
+ hu.elte.refjava.control.library,
+ hu.elte.refjava.control.utils,
+ hu.elte.refjava.control.wizards
diff --git a/hu.elte.refjava.control/src/hu/elte/refjava/control/utils/SelectionNodeFinder.xtend b/hu.elte.refjava.control/src/hu/elte/refjava/control/utils/SelectionNodeFinder.xtend
index 13f6270..5c410ae 100644
--- a/hu.elte.refjava.control/src/hu/elte/refjava/control/utils/SelectionNodeFinder.xtend
+++ b/hu.elte.refjava.control/src/hu/elte/refjava/control/utils/SelectionNodeFinder.xtend
@@ -17,7 +17,7 @@ class SelectionNodeFinder {
if (coveringNode == finder.coveredNode) {
return #[coveringNode]
}
-
+
val selectionRange = Range.closed(selection.offset, selection.offset + selection.length)
return coveringNode.children.filter [
val nodeRange = Range.closed(startPosition, startPosition + length)
@@ -36,5 +36,4 @@ class SelectionNodeFinder {
def private static dispatch getChildren(ASTNode coveringNode) {
#[coveringNode]
}
-
}
diff --git a/hu.elte.refjava.control/src/hu/elte/refjava/control/utils/TypeDeclarationGetter.xtend b/hu.elte.refjava.control/src/hu/elte/refjava/control/utils/TypeDeclarationGetter.xtend
new file mode 100644
index 0000000..3bdecf5
--- /dev/null
+++ b/hu.elte.refjava.control/src/hu/elte/refjava/control/utils/TypeDeclarationGetter.xtend
@@ -0,0 +1,39 @@
+package hu.elte.refjava.control.utils
+
+import org.eclipse.core.resources.ResourcesPlugin
+import org.eclipse.jdt.core.dom.TypeDeclaration
+import java.util.List
+import org.eclipse.jdt.core.dom.CompilationUnit
+import org.eclipse.jdt.core.JavaCore
+import org.eclipse.jdt.core.dom.ASTParser
+import org.eclipse.jdt.core.dom.AST
+
+class TypeDeclarationGetter {
+ def static getAllTypeDeclarationInWorkspace() {
+ val workspace = ResourcesPlugin.workspace
+ val root = workspace.root
+ val projects = root.projects
+
+ val List allTypeDeclInWorkSpace = newArrayList
+ for (project : projects) {
+ val javaProject = JavaCore.create(project)
+ val packages = javaProject.getPackageFragments()
+ for (package : packages) {
+ val iCompUnits = package.compilationUnits
+ val List allCompUnit = newArrayList
+ for (iCompUnit : iCompUnits) {
+ val parser = ASTParser.newParser(AST.JLS12);
+ parser.resolveBindings = true
+ parser.source = iCompUnit;
+ val compUnit = parser.createAST(null) as CompilationUnit;
+ allCompUnit.add(compUnit)
+ }
+
+ for (compUnit : allCompUnit) {
+ allTypeDeclInWorkSpace.addAll(compUnit.types)
+ }
+ }
+ }
+ allTypeDeclInWorkSpace
+ }
+}
\ No newline at end of file
diff --git a/hu.elte.refjava.control/src/hu/elte/refjava/control/wizards/RefJavaWizard.xtend b/hu.elte.refjava.control/src/hu/elte/refjava/control/wizards/RefJavaWizard.xtend
index e1d464f..784ee96 100644
--- a/hu.elte.refjava.control/src/hu/elte/refjava/control/wizards/RefJavaWizard.xtend
+++ b/hu.elte.refjava.control/src/hu/elte/refjava/control/wizards/RefJavaWizard.xtend
@@ -2,6 +2,7 @@ package hu.elte.refjava.control.wizards
import hu.elte.refjava.api.Refactoring
import hu.elte.refjava.control.utils.SelectionNodeFinder
+import hu.elte.refjava.control.utils.TypeDeclarationGetter
import java.net.URLClassLoader
import org.eclipse.jdt.core.ICompilationUnit
import org.eclipse.jdt.core.dom.AST
@@ -42,25 +43,27 @@ class RefJavaWizard extends Wizard {
val editor = PlatformUI.workbench.activeWorkbenchWindow.activePage.activeEditor
if (editor instanceof ITextEditor) {
-
+
val selection = editor.selectionProvider.selection
if (selection instanceof TextSelection) {
-
+
+ val allTypeDeclarationInWorkSpace = TypeDeclarationGetter.allTypeDeclarationInWorkspace
+
val typeRoot = JavaUI.getEditorInputTypeRoot(editor.editorInput)
val iCompUnit = typeRoot.getAdapter(ICompilationUnit)
- val parser = ASTParser.newParser(AST.JLS10)
+ val parser = ASTParser.newParser(AST.JLS12)
parser.setResolveBindings(true)
parser.source = iCompUnit
val compUnit = parser.createAST(null) as CompilationUnit
-
+
val selectedNodes = SelectionNodeFinder.selectedNodes(selection, compUnit)
-
+
val provider = editor.documentProvider
val document = provider.getDocument(editor.editorInput)
-
- refactoringInstance.init(selectedNodes, document)
- val status = refactoringInstance.apply
+
+ refactoringInstance.init(selectedNodes, document, allTypeDeclarationInWorkSpace)
+ val status = refactoringInstance.apply
switch status {
case SUCCESS:
MessageDialog.openInformation(dialog.shell, "Success",
@@ -71,7 +74,6 @@ class RefJavaWizard extends Wizard {
}
}
}
-
return true;
}
diff --git a/hu.elte.refjava.control/src/hu/elte/refjava/control/wizards/RefJavaWizardPage.xtend b/hu.elte.refjava.control/src/hu/elte/refjava/control/wizards/RefJavaWizardPage.xtend
index 3864fa3..283cd83 100644
--- a/hu.elte.refjava.control/src/hu/elte/refjava/control/wizards/RefJavaWizardPage.xtend
+++ b/hu.elte.refjava.control/src/hu/elte/refjava/control/wizards/RefJavaWizardPage.xtend
@@ -46,7 +46,7 @@ class RefJavaWizardPage extends WizardPage {
.flatMap[compilationUnits.toList]
.map [
// do not optimize
- val parser = ASTParser.newParser(AST.JLS10)
+ val parser = ASTParser.newParser(AST.JLS12)
parser.setResolveBindings(true)
parser.source = it
parser.createAST(null) as CompilationUnit
diff --git a/hu.elte.refjava.examples/.classpath b/hu.elte.refjava.examples/.classpath
index 7142ac0..50ec8bc 100644
--- a/hu.elte.refjava.examples/.classpath
+++ b/hu.elte.refjava.examples/.classpath
@@ -2,8 +2,12 @@
-
+
+
+
+
+
diff --git a/hu.elte.refjava.examples/.settings/org.eclipse.jdt.core.prefs b/hu.elte.refjava.examples/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..34bf367
--- /dev/null
+++ b/hu.elte.refjava.examples/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,10 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=12
+org.eclipse.jdt.core.compiler.compliance=12
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=12
diff --git a/hu.elte.refjava.examples/src/hu/elte/refjava/examples/Target.java b/hu.elte.refjava.examples/src/hu/elte/refjava/examples/Target.java
index a3e7a32..2ba3684 100644
--- a/hu.elte.refjava.examples/src/hu/elte/refjava/examples/Target.java
+++ b/hu.elte.refjava.examples/src/hu/elte/refjava/examples/Target.java
@@ -1,18 +1,22 @@
package hu.elte.refjava.examples;
-public class Target {
- int a;
+class A {
+}
- /*
- * Insert a new block after the 3rd statement
- * and move the first 3 statements into it.
- * Change the 4th 'a' reference to 'this.a'
- * and try again the last step.
- */
+class B extends A {
+ int b;
+ int a;
+
void f() {
- int a = 5;
- int b = a;
- System.out.println(a + b);
- System.out.println(a);
+ int x = 1;
+ int a;
+ a = x;
+ g();
+ int y = 0;
+ a = y;
}
-}
+
+ void g() {
+ a = b = 0;
+ }
+}
\ No newline at end of file
diff --git a/hu.elte.refjava.examples/src/hu/elte/refjava/examples/refactorings.refjava b/hu.elte.refjava.examples/src/hu/elte/refjava/examples/refactorings.refjava
index cab1059..10179d1 100644
--- a/hu.elte.refjava.examples/src/hu/elte/refjava/examples/refactorings.refjava
+++ b/hu.elte.refjava.examples/src/hu/elte/refjava/examples/refactorings.refjava
@@ -1,20 +1,73 @@
package hu.elte.refjava.examples;
-local refactoring identity()
- #s..
- ~~~~
- #s..
-
-local refactoring insertEmptyBlockAfter()
- #s..
- ~~~~~~~~~
- #s.. ; {}
-
-local refactoring moveIntoNextBlock()
- #s1 ; { #s2.. } ; #s3
- ~~~~~~~~~~~~~~~~~~~~~
- { #s1 ; #s2.. } ; #s3
+local refactoring introduceEmptyBlockAfter()
+ target
+ ~~~~~~~
+ target ; {}
+
+
+block refactoring moveIntoNextBlock()
+ target ; { #s1.. } ; #s2..
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ { target ; #s1.. } ; #s2..
+when
+ precondition
+ isSingle(target)
+ && if(isVariableDeclaration(target)) { !isReferencedIn(asVariableDeclaration(target), #s2..) }
+ else true
+
+
+block refactoring moveToTop()
+ #s.. ; target
+ ~~~~~~~~~~~~~
+ target ; #s..
+target
+ type#T name#N
+
+
+lambda refactoring wrapInVoidLambda()
+ #s..
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ new name#N() { public void apply() { #s.. } }.apply()
+when
+ precondition
+ !containsValueReturn(#s..)
+ && if (containsVoidReturn(#s..)) { isLastExecutionNode(getVoidReturn(#s..)) }
+ else true
+
+
+lambda refactoring lambdaModfification()
+ new name#N1() { public void apply() { #s.. } }.apply()
+ ~~~~~~
+ new name#N2() { public void apply() { #s.. } }.apply()
when
- !isVariableDeclaration(#s1) ||
- !isReferencedIn(asVariableDeclaration(#s1),
- blockRemainder(#s3))
+ assignment
+ name#N2 = "newLambda2"
+ precondition
+ isFresh(name#N2)
+
+
+class refactoring newMethod()
+ new name#N() { public void apply(parameter#P..) { #s2.. } }.apply(argument#A..)
+ ~~~~~~
+ newMethod(argument#A..)
+definition in class
+ void newMethod(parameter#P..) { #s2.. }
+
+
+class refactoring liftField()
+ visibility#V type#T name#N ;
+ ~~~~~~~
+ nothing
+definition in super
+ target
+
+
+class refactoring liftMethod()
+ visibility#V type#T name#N(parameter#P..) { #s.. }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ nothing
+definition in super
+ target
+
+
\ No newline at end of file
diff --git a/hu.elte.refjava.lang.ide/.classpath b/hu.elte.refjava.lang.ide/.classpath
index 8018385..bc001b4 100644
--- a/hu.elte.refjava.lang.ide/.classpath
+++ b/hu.elte.refjava.lang.ide/.classpath
@@ -1,9 +1,9 @@
+
+
-
-
diff --git a/hu.elte.refjava.lang.ide/.settings/org.eclipse.jdt.core.prefs b/hu.elte.refjava.lang.ide/.settings/org.eclipse.jdt.core.prefs
index dd5a2bb..3efb014 100644
--- a/hu.elte.refjava.lang.ide/.settings/org.eclipse.jdt.core.prefs
+++ b/hu.elte.refjava.lang.ide/.settings/org.eclipse.jdt.core.prefs
@@ -9,8 +9,8 @@ org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nul
org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=10
-org.eclipse.jdt.core.compiler.compliance=10
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.APILeak=warning
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
@@ -22,6 +22,7 @@ org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=ignore
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
@@ -67,6 +68,7 @@ org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=igno
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
@@ -105,4 +107,4 @@ org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.release=enabled
-org.eclipse.jdt.core.compiler.source=10
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/hu.elte.refjava.lang.ide/META-INF/MANIFEST.MF b/hu.elte.refjava.lang.ide/META-INF/MANIFEST.MF
index eea8fc8..d0f4884 100644
--- a/hu.elte.refjava.lang.ide/META-INF/MANIFEST.MF
+++ b/hu.elte.refjava.lang.ide/META-INF/MANIFEST.MF
@@ -9,8 +9,12 @@ Bundle-ActivationPolicy: lazy
Require-Bundle: hu.elte.refjava,
org.eclipse.xtext.ide,
org.eclipse.xtext.xbase.ide,
- org.antlr.runtime;bundle-version="[3.2.0,3.2.1)"
-Bundle-RequiredExecutionEnvironment: JavaSE-10
-Export-Package: hu.elte.refjava.lang.ide.contentassist.antlr,
+ org.antlr.runtime;bundle-version="[3.2.0,3.2.1)",
+ com.google.guava,
+ org.eclipse.xtext.xbase.lib,
+ org.eclipse.xtend.lib,
+ org.eclipse.xtend.lib.macro
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Export-Package: hu.elte.refjava.lang.ide,
+ hu.elte.refjava.lang.ide.contentassist.antlr,
hu.elte.refjava.lang.ide.contentassist.antlr.internal
-
diff --git a/hu.elte.refjava.lang.ide/src/hu/elte/refjava/lang/ide/RefJavaIdeSetup.xtend b/hu.elte.refjava.lang.ide/src/hu/elte/refjava/lang/ide/RefJavaIdeSetup.xtend
index 4899d68..676cd03 100644
--- a/hu.elte.refjava.lang.ide/src/hu/elte/refjava/lang/ide/RefJavaIdeSetup.xtend
+++ b/hu.elte.refjava.lang.ide/src/hu/elte/refjava/lang/ide/RefJavaIdeSetup.xtend
@@ -16,5 +16,4 @@ class RefJavaIdeSetup extends RefJavaStandaloneSetup {
override createInjector() {
Guice.createInjector(Modules2.mixin(new RefJavaRuntimeModule, new RefJavaIdeModule))
}
-
}
diff --git a/hu.elte.refjava.lang.tests/.classpath b/hu.elte.refjava.lang.tests/.classpath
new file mode 100644
index 0000000..6b3cdb9
--- /dev/null
+++ b/hu.elte.refjava.lang.tests/.classpath
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hu.elte.refjava.lang.tests/.gitignore b/hu.elte.refjava.lang.tests/.gitignore
new file mode 100644
index 0000000..b778aa2
--- /dev/null
+++ b/hu.elte.refjava.lang.tests/.gitignore
@@ -0,0 +1,4 @@
+bin/
+bin-test/
+src-gen/
+xtend-gen/
diff --git a/hu.elte.refjava.lang.tests/.project b/hu.elte.refjava.lang.tests/.project
new file mode 100644
index 0000000..a1eab17
--- /dev/null
+++ b/hu.elte.refjava.lang.tests/.project
@@ -0,0 +1,34 @@
+
+
+ hu.elte.refjava.lang.tests
+
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.pde.ManifestBuilder
+
+
+
+
+ org.eclipse.pde.SchemaBuilder
+
+
+
+
+
+ org.eclipse.xtext.ui.shared.xtextNature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.pde.PluginNature
+
+
diff --git a/hu.elte.refjava.lang.tests/.settings/org.eclipse.core.resources.prefs b/hu.elte.refjava.lang.tests/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..fdaa299
--- /dev/null
+++ b/hu.elte.refjava.lang.tests/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=windows-1250
diff --git a/hu.elte.refjava.lang.tests/.settings/org.eclipse.jdt.core.prefs b/hu.elte.refjava.lang.tests/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..e50443c
--- /dev/null
+++ b/hu.elte.refjava.lang.tests/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,15 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/hu.elte.refjava.lang.tests/.settings/org.eclipse.ltk.core.refactoring.prefs b/hu.elte.refjava.lang.tests/.settings/org.eclipse.ltk.core.refactoring.prefs
new file mode 100644
index 0000000..b196c64
--- /dev/null
+++ b/hu.elte.refjava.lang.tests/.settings/org.eclipse.ltk.core.refactoring.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
diff --git a/hu.elte.refjava.lang.tests/META-INF/MANIFEST.MF b/hu.elte.refjava.lang.tests/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..59ac254
--- /dev/null
+++ b/hu.elte.refjava.lang.tests/META-INF/MANIFEST.MF
@@ -0,0 +1,31 @@
+Manifest-Version: 1.0
+Automatic-Module-Name: hu.elte.refjava.lang.tests
+Bundle-ManifestVersion: 2
+Bundle-Name: hu.elte.refjava.lang.tests
+Bundle-Vendor: My Company
+Bundle-Version: 1.0.0.qualifier
+Bundle-SymbolicName: hu.elte.refjava.lang.tests;singleton:=true
+Bundle-ActivationPolicy: lazy
+Require-Bundle: hu.elte.refjava,
+ org.junit.jupiter.api;bundle-version="[5.0.0,6.0.0)",
+ org.eclipse.xtext.testing,
+ org.eclipse.xtext.xbase.testing,
+ org.objectweb.asm;bundle-version="[7.1.0,7.2.0)";resolution:=optional,
+ org.eclipse.jdt.core;bundle-version="3.19.0",
+ org.eclipse.xtext.xbase.lib;bundle-version="2.14.0",
+ com.google.guava,
+ org.eclipse.xtext.xbase.lib;bundle-version="2.14.0",
+ org.eclipse.xtend.lib,
+ org.eclipse.xtend.lib.macro,
+ org.eclipse.ui.editors;bundle-version="3.11.200",
+ org.eclipse.jface.text;bundle-version="3.14.0",
+ org.eclipse.core.runtime;bundle-version="3.15.0",
+ org.eclipse.jdt.core;bundle-version="3.15.0",
+ org.eclipse.jdt.ui;bundle-version="3.15.0",
+ org.eclipse.core.resources;bundle-version="3.13.100",
+ org.eclipse.xtext.ui;bundle-version="2.15.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Export-Package: hu.elte.refjava.lang.tests;x-internal=true,
+ hu.elte.refjava.lang.tests.api,
+ hu.elte.refjava.lang.tests.compiler,
+ hu.elte.refjava.lang.tests.parser
diff --git a/hu.elte.refjava.lang.tests/build.properties b/hu.elte.refjava.lang.tests/build.properties
new file mode 100644
index 0000000..f8b77a8
--- /dev/null
+++ b/hu.elte.refjava.lang.tests/build.properties
@@ -0,0 +1,7 @@
+source.. = src/,\
+ src-gen/,\
+ xtend-gen/
+bin.includes = .,\
+ META-INF/
+bin.excludes = **/*.xtend
+jars.compile.order = .
diff --git a/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/RefJavaParsingTest.xtend b/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/RefJavaParsingTest.xtend
new file mode 100644
index 0000000..5489dda
--- /dev/null
+++ b/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/RefJavaParsingTest.xtend
@@ -0,0 +1,14 @@
+/*
+ * generated by Xtext
+ */
+package hu.elte.refjava.lang.tests
+
+import org.eclipse.xtext.testing.InjectWith
+import org.eclipse.xtext.testing.extensions.InjectionExtension
+import org.junit.jupiter.api.^extension.ExtendWith
+
+@ExtendWith(InjectionExtension)
+@InjectWith(RefJavaInjectorProvider)
+class RefJavaParsingTest {
+
+}
diff --git a/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/api/ASTBuilderTests.xtend b/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/api/ASTBuilderTests.xtend
new file mode 100644
index 0000000..18643bf
--- /dev/null
+++ b/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/api/ASTBuilderTests.xtend
@@ -0,0 +1,182 @@
+package hu.elte.refjava.lang.tests.api
+
+import hu.elte.refjava.lang.refJava.Visibility
+import hu.elte.refjava.lang.tests.RefJavaInjectorProvider
+import java.util.List
+import java.util.Map
+import org.eclipse.jdt.core.dom.ASTNode
+import org.eclipse.jdt.core.dom.CompilationUnit
+import org.eclipse.jdt.core.dom.Expression
+import org.eclipse.jdt.core.dom.ExpressionStatement
+import org.eclipse.jdt.core.dom.FieldDeclaration
+import org.eclipse.jdt.core.dom.MethodDeclaration
+import org.eclipse.jdt.core.dom.MethodInvocation
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration
+import org.eclipse.jdt.core.dom.Type
+import org.eclipse.jdt.core.dom.TypeDeclaration
+import org.eclipse.jdt.core.dom.VariableDeclarationStatement
+import org.eclipse.xtext.testing.InjectWith
+import org.eclipse.xtext.testing.extensions.InjectionExtension
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.^extension.ExtendWith
+
+import static org.junit.jupiter.api.Assertions.*
+
+@ExtendWith(InjectionExtension)
+@InjectWith(RefJavaInjectorProvider)
+package class ASTBuilderTests {
+
+ Map> bindings = newHashMap
+ Map nameBindings = newHashMap
+ Map typeBindings = newHashMap
+ Map> parameterBindings = newHashMap
+ Map visibilityBindings = newHashMap
+ Map> argumentBindings = newHashMap
+ String typeRefString = null
+
+ List replacement
+ CompilationUnit source
+
+ @Test
+ def void variableDeclarationBuilderTest() {
+
+ source = TestUtils.getCompliationUnit('''class A { public void f() { int a; char b; String str; } }''')
+ val sourceVariableDeclarations = ((source.types.head as TypeDeclaration).bodyDeclarations.head as MethodDeclaration).body.statements.map[it as VariableDeclarationStatement]
+ var List replacementVariableDeclarations
+
+ // #1
+ typeRefString = "void|int|char|java.lang.String|"
+ replacement = TestUtils.testBuilder('''public void f() { int a ; char b ; String str }''',
+ bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+ assertTrue(replacement.head instanceof MethodDeclaration)
+ replacementVariableDeclarations = (replacement.head as MethodDeclaration).body.statements
+ for(var int i = 0; i < replacementVariableDeclarations.size; i++) {
+ assertTrue(replacementVariableDeclarations.get(i) instanceof VariableDeclarationStatement)
+ assertEquals(replacementVariableDeclarations.get(i).toString, sourceVariableDeclarations.get(i).toString)
+ }
+
+ // #2
+ typeRefString = "void|"
+ nameBindings.put("N1", "a")
+ nameBindings.put("N2", "b")
+ nameBindings.put("N3", "str")
+ typeBindings.put("T1", sourceVariableDeclarations.get(0).type)
+ typeBindings.put("T2", sourceVariableDeclarations.get(1).type)
+ typeBindings.put("T3", sourceVariableDeclarations.get(2).type)
+ replacement = TestUtils.testBuilder('''public void f() { type#T1 name#N1 ; type#T2 name#N2 ; type#T3 name#N3 }''',
+ bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+ assertTrue(replacement.head instanceof MethodDeclaration)
+ replacementVariableDeclarations = (replacement.head as MethodDeclaration).body.statements
+ for(var int i = 0; i < replacementVariableDeclarations.size; i++) {
+ assertTrue(replacementVariableDeclarations.get(i) instanceof VariableDeclarationStatement)
+ assertEquals(sourceVariableDeclarations.get(i).toString, replacementVariableDeclarations.get(i).toString)
+ }
+ }
+
+ @Test
+ def void fieldDeclarationBuilderTest() {
+
+ source = TestUtils.getCompliationUnit('''class A { public int a; private char b; String str }''')
+ val sourceFieldDeclarations = (source.types.head as TypeDeclaration).bodyDeclarations.map[it as FieldDeclaration]
+ var List replacementFieldDeclarations
+
+ // #1
+ typeRefString = "int|char|java.lang.String|"
+ replacement = TestUtils.testBuilder('''public int a ; private char b ; String str''',
+ bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+ assertTrue(replacement.forall[it instanceof FieldDeclaration])
+ replacementFieldDeclarations = replacement.map[it as FieldDeclaration]
+ for(var int i = 0; i < replacementFieldDeclarations.size; i++) {
+ assertEquals(sourceFieldDeclarations.get(i).toString, replacementFieldDeclarations.get(i).toString)
+ }
+
+ // #2
+ typeRefString = null
+ nameBindings.put("N1", "a")
+ nameBindings.put("N2", "b")
+ nameBindings.put("N3", "str")
+ typeBindings.put("T1", sourceFieldDeclarations.get(0).type)
+ typeBindings.put("T2", sourceFieldDeclarations.get(1).type)
+ typeBindings.put("T3", sourceFieldDeclarations.get(2).type)
+ visibilityBindings.put("V1", Visibility.PUBLIC)
+ visibilityBindings.put("V2", Visibility.PRIVATE)
+ visibilityBindings.put("V3", Visibility.PACKAGE)
+ replacement = TestUtils.testBuilder('''visibility#V1 type#T1 name#N1 ; visibility#V2 type#T2 name#N2 ; visibility#V3 type#T3 name#N3''',
+ bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+ assertTrue(replacement.forall[it instanceof FieldDeclaration])
+ replacementFieldDeclarations = replacement.map[it as FieldDeclaration]
+ for(var int i = 0; i < replacementFieldDeclarations.size; i++) {
+ assertEquals(sourceFieldDeclarations.get(i).toString, replacementFieldDeclarations.get(i).toString)
+ }
+ }
+
+ @Test
+ def void methodDeclarationBuilderTest() {
+
+ source = TestUtils.getCompliationUnit('''class A { public void f(int a){ } private short g(boolean l, char b){ } String h(){ } }''')
+ val sourceMethodDeclarations = (source.types.head as TypeDeclaration).bodyDeclarations.map[it as MethodDeclaration]
+ var List replacementMethodDeclarations
+
+ // #1
+ typeRefString = "void|int|short|boolean|char|java.lang.String|"
+ replacement = TestUtils.testBuilder('''public void f(int a){ } ; private short g(boolean l, char b){ } ; String h(){ }''',
+ bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+ assertTrue(replacement.forall[it instanceof MethodDeclaration])
+ replacementMethodDeclarations = replacement.map[it as MethodDeclaration]
+ for(var int i = 0; i < replacementMethodDeclarations.size; i++) {
+ assertEquals(sourceMethodDeclarations.get(i).toString, replacementMethodDeclarations.get(i).toString)
+ }
+
+ // #2
+ typeRefString = null
+ nameBindings.put("N1", "f")
+ nameBindings.put("N2", "g")
+ nameBindings.put("N3", "h")
+ typeBindings.put("T1", sourceMethodDeclarations.get(0).returnType2)
+ typeBindings.put("T2", sourceMethodDeclarations.get(1).returnType2)
+ typeBindings.put("T3", sourceMethodDeclarations.get(2).returnType2)
+ visibilityBindings.put("V1", Visibility.PUBLIC)
+ visibilityBindings.put("V2", Visibility.PRIVATE)
+ visibilityBindings.put("V3", Visibility.PACKAGE)
+ parameterBindings.put("P1", sourceMethodDeclarations.get(0).parameters)
+ parameterBindings.put("P2", sourceMethodDeclarations.get(1).parameters)
+ parameterBindings.put("P3", sourceMethodDeclarations.get(2).parameters)
+ replacement = TestUtils.testBuilder('''visibility#V1 type#T1 name#N1(parameter#P1..){ } ; visibility#V2 type#T2 name#N2(parameter#P2..){ } ; visibility#V3 type#T3 name#N3(parameter#P3..){ }''',
+ bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+ assertTrue(replacement.forall[it instanceof MethodDeclaration])
+ replacementMethodDeclarations = replacement.map[it as MethodDeclaration]
+ for(var int i = 0; i < replacementMethodDeclarations.size; i++) {
+ assertEquals(sourceMethodDeclarations.get(i).toString, replacementMethodDeclarations.get(i).toString)
+ }
+ }
+
+ @Test
+ def void methodInvocetionAndConstructorCallBuilderTest() {
+
+ source = TestUtils.getCompliationUnit('''class A { public void f() { new F() { public void apply(int a, char b) {} }.apply(a, b); new G() { public void apply() {} }.apply(); } int a = 1; char b = 'a'; }''')
+ val sourceMethodInvocations = ((source.types.head as TypeDeclaration).bodyDeclarations.head as MethodDeclaration).body.statements.map[(it as ExpressionStatement).expression as MethodInvocation]
+ var List replacementMethodInvocations
+
+ // #1
+ typeRefString = "void|int|char|void|"
+ argumentBindings.put("A1", sourceMethodInvocations.get(0).arguments)
+ replacement = TestUtils.testBuilder('''new F() { public void apply(int a, char b) {} }.apply(argument#A1..) ; new G() { public void apply() {} }.apply()''',
+ bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+ assertTrue(replacement.forall[it instanceof ExpressionStatement] && replacement.forall[(it as ExpressionStatement).expression instanceof MethodInvocation])
+ replacementMethodInvocations = replacement.map[(it as ExpressionStatement).expression as MethodInvocation]
+ for(var int i = 0; i < replacementMethodInvocations.size; i++) {
+ assertEquals(sourceMethodInvocations.get(i).toString, replacementMethodInvocations.get(i).toString)
+ }
+
+ // #2
+ nameBindings.put("N1", "F")
+ nameBindings.put("N2", "G")
+ replacement = TestUtils.testBuilder('''new name#N1() { public void apply(int a, char b) {} }.apply(argument#A1..) ; new name#N2() { public void apply() {} }.apply()''',
+ bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+ assertTrue(replacement.forall[it instanceof ExpressionStatement] && replacement.forall[(it as ExpressionStatement).expression instanceof MethodInvocation])
+ replacementMethodInvocations = replacement.map[(it as ExpressionStatement).expression as MethodInvocation]
+ for(var int i = 0; i < replacementMethodInvocations.size; i++) {
+ assertEquals(sourceMethodInvocations.get(i).toString, replacementMethodInvocations.get(i).toString)
+ }
+ }
+}
\ No newline at end of file
diff --git a/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/api/PatternMatcherTests.xtend b/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/api/PatternMatcherTests.xtend
new file mode 100644
index 0000000..c72fccc
--- /dev/null
+++ b/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/api/PatternMatcherTests.xtend
@@ -0,0 +1,242 @@
+package hu.elte.refjava.lang.tests.api
+
+import hu.elte.refjava.lang.refJava.Visibility
+import hu.elte.refjava.lang.tests.RefJavaInjectorProvider
+import java.util.List
+import java.util.Map
+import org.eclipse.jdt.core.dom.ClassInstanceCreation
+import org.eclipse.jdt.core.dom.Expression
+import org.eclipse.jdt.core.dom.ExpressionStatement
+import org.eclipse.jdt.core.dom.FieldDeclaration
+import org.eclipse.jdt.core.dom.MethodDeclaration
+import org.eclipse.jdt.core.dom.MethodInvocation
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration
+import org.eclipse.jdt.core.dom.Type
+import org.eclipse.jdt.core.dom.TypeDeclaration
+import org.eclipse.jdt.core.dom.VariableDeclarationStatement
+import org.eclipse.xtext.testing.InjectWith
+import org.eclipse.xtext.testing.extensions.InjectionExtension
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.^extension.ExtendWith
+
+@ExtendWith(InjectionExtension)
+@InjectWith(RefJavaInjectorProvider)
+package class PatternMatcherTests {
+
+ Map nameBindings = newHashMap
+ Map typeBindings = newHashMap
+ Map> parameterBindings = newHashMap
+ Map visibilityBindings = newHashMap
+ Map> argumentBindings = newHashMap
+ String typeRefString = null
+
+ @Test
+ def void variableDeclarationMatcherTest() {
+ // #1
+ TestUtils.testMatcher('''type#T1 name#N1 ; type#T2 name#N2 ;''',
+ '''
+ class A {
+ void f(){
+ int a;
+ char b;
+ }
+ }
+ ''',
+ "block",
+ nameBindings , typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+
+ // #2
+ val compUnit = TestUtils.getCompliationUnit("class A { void f(){ int a; char b; } }")
+ val methodBody = ((compUnit.types.head as TypeDeclaration).bodyDeclarations.head as MethodDeclaration).body.statements
+ nameBindings.put("N1", "a")
+ nameBindings.put("N2", "b")
+ typeBindings.put("T1", (methodBody.head as VariableDeclarationStatement).type )
+ typeBindings.put("T2", (methodBody.last as VariableDeclarationStatement).type )
+ TestUtils.testMatcher('''type#T1 name#N1 ; type#T2 name#N2 ;''',
+ '''
+ class A {
+ void f(){
+ int a;
+ char b;
+ }
+ }
+ ''',
+ "block",
+ nameBindings , typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+
+ // #3
+ typeRefString="int|char|java.lang.String|"
+ TestUtils.testMatcher('''int a ; char b ; String c ;''',
+ '''
+ class A {
+ void f(){
+ int a;
+ char b;
+ String c;
+ }
+ }
+ ''',
+ "block",
+ nameBindings , typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+ }
+
+ @Test
+ def void fieldDeclarationMatcherTest() {
+ // #1
+ TestUtils.testMatcher('''visibility#V1 type#T1 name#N1 ; visibility#V2 type#T2 name#N2 ;''',
+ '''
+ class A {
+ public int a;
+ private char b;
+ }
+ ''',
+ "class",
+ nameBindings , typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+
+ // #2
+ val compUnit = TestUtils.getCompliationUnit("class A { public int a; private char b; }")
+ val fieldDeclarations = (compUnit.types.head as TypeDeclaration).bodyDeclarations
+ nameBindings.put("N1", "a")
+ nameBindings.put("N2", "b")
+ typeBindings.put("T1", (fieldDeclarations.head as FieldDeclaration).type )
+ typeBindings.put("T2", (fieldDeclarations.last as FieldDeclaration).type )
+ visibilityBindings.put("V1", Visibility.PUBLIC)
+ visibilityBindings.put("V2", Visibility.PRIVATE)
+ TestUtils.testMatcher('''visibility#V1 type#T1 name#N1 ; visibility#V2 type#T2 name#N2 ;''',
+ '''
+ class A {
+ public int a ;
+ private char b;
+ }
+ ''',
+ "class",
+ nameBindings , typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+
+ // #3
+ typeRefString = "int|char|"
+ TestUtils.testMatcher('''public int a ; private char b ;''',
+ '''
+ class A {
+ public int a ;
+ private char b;
+ }
+ ''',
+ "class",
+ nameBindings , typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+ }
+
+ @Test
+ def void methodDeclarationMatcherTest() {
+ // #1
+ TestUtils.testMatcher('''visibility#V1 type#T1 name#N1(parameter#P1..) {} ; visibility#V2 type#T2 name#N2(parameter#P2..) {} ;''',
+ '''
+ class A {
+ public void f(int a, String str) {}
+ private int g() {}
+ }
+ ''',
+ "class",
+ nameBindings , typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+
+ // #2
+ val compUnit = TestUtils.getCompliationUnit("class A { public void f(int a, String str) {} private int g() {} }")
+ val methodDeclarations = (compUnit.types.head as TypeDeclaration).bodyDeclarations
+ nameBindings.put("N1", "f")
+ nameBindings.put("N2", "g")
+ typeBindings.put("T1", (methodDeclarations.head as MethodDeclaration).returnType2 )
+ typeBindings.put("T2", (methodDeclarations.last as MethodDeclaration).returnType2 )
+ visibilityBindings.put("V1", Visibility.PUBLIC)
+ visibilityBindings.put("V2", Visibility.PRIVATE)
+ parameterBindings.put("P1", (methodDeclarations.head as MethodDeclaration).parameters)
+ parameterBindings.put("P2", (methodDeclarations.last as MethodDeclaration).parameters)
+
+ TestUtils.testMatcher('''visibility#V1 type#T1 name#N1(parameter#P1..) {} ; visibility#V2 type#T2 name#N2(parameter#P2..) {} ;''',
+ '''
+ class A {
+ public void f(int a, String str) {}
+ private int g() {}
+ }
+ ''',
+ "class",
+ nameBindings , typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+
+ // #3
+ typeRefString = "void|int|java.lang.String|int|"
+ TestUtils.testMatcher('''public void f(int a, String str) {} ; private int g() {} ;''',
+ '''
+ class A {
+ public void f(int a, String str) {}
+ private int g() {}
+ }
+ ''',
+ "class",
+ nameBindings , typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+ }
+
+ @Test
+ def void methodInvocationAndConstructorCallMatcherTest() {
+ // #1
+ TestUtils.testMatcher('''new name#N1() { visibility#V1 type#T1 name#N2(parameter#P1..) {} }.name#N2(argument#A1..)''',
+ '''
+ class A {
+ void f() {
+ new F() {
+ public void apply(int a) {}
+ }.apply(a);
+ }
+ public int a = 1;
+ }
+ ''',
+ "block",
+ nameBindings , typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+
+ // #2
+ val compUnit = TestUtils.getCompliationUnit("class A { public void f() { new F() { public void apply(int a, char b) {} }.apply(a, b); } int a = 1; char b = 'a'; }")
+ val methodInvocation = (((compUnit.types.head as TypeDeclaration).bodyDeclarations.head as MethodDeclaration).body.statements.head as ExpressionStatement).expression as MethodInvocation
+ val method = (((((compUnit.types.head as TypeDeclaration).bodyDeclarations.head as MethodDeclaration).body.statements.head as ExpressionStatement)
+ .expression as MethodInvocation)
+ .expression as ClassInstanceCreation)
+ .anonymousClassDeclaration.bodyDeclarations.head as MethodDeclaration
+ nameBindings.put("N1", "F")
+ nameBindings.put("N2", "apply")
+ typeBindings.put("T1", method.returnType2)
+ visibilityBindings.put("V1", Visibility.PUBLIC)
+ parameterBindings.put("P1", method.parameters)
+ argumentBindings.put("A1", methodInvocation.arguments)
+ TestUtils.testMatcher('''new name#N1() { visibility#V1 type#T1 name#N2(parameter#P1..) {} }.name#N2(argument#A1..)''',
+ '''
+ class A {
+ void f() {
+ new F() {
+ public void apply(int a, char b) {}
+ }.apply(a, b);
+ }
+ int a = 1;
+ char b = 'a';
+ }
+ ''',
+ "block",
+ nameBindings , typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+
+ // #3
+ typeRefString = "void|int|char|"
+ TestUtils.testMatcher('''new F() { public void apply(int a, char b) {} }.apply(argument#A1..)''',
+ '''
+ class A {
+ void f() {
+ new F() {
+ public void apply(int a, char b) {}
+ }.apply(a, b);
+ }
+ }
+ int a = 1;
+ char b = 'a';
+ ''',
+ "block",
+ nameBindings , typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/api/TestUtils.xtend b/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/api/TestUtils.xtend
new file mode 100644
index 0000000..6217535
--- /dev/null
+++ b/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/api/TestUtils.xtend
@@ -0,0 +1,52 @@
+package hu.elte.refjava.lang.tests.api
+
+import hu.elte.refjava.api.patterns.ASTBuilder
+import hu.elte.refjava.api.patterns.PatternMatcher
+import hu.elte.refjava.api.patterns.PatternParser
+import hu.elte.refjava.lang.refJava.Visibility
+import java.util.List
+import java.util.Map
+import org.eclipse.jdt.core.dom.AST
+import org.eclipse.jdt.core.dom.ASTParser
+import org.eclipse.jdt.core.dom.CompilationUnit
+import org.eclipse.jdt.core.dom.Expression
+import org.eclipse.jdt.core.dom.MethodDeclaration
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration
+import org.eclipse.jdt.core.dom.Type
+import org.eclipse.jdt.core.dom.TypeDeclaration
+
+import static org.junit.jupiter.api.Assertions.*
+import org.eclipse.jdt.core.dom.ASTNode
+
+class TestUtils {
+
+ def static getCompliationUnit(String str) {
+ val parser = ASTParser.newParser(AST.JLS12);
+ parser.setUnitName("test.java");
+ parser.setEnvironment(null, null, null, true);
+ parser.resolveBindings = true
+ parser.source = str.toCharArray
+ val newCompUnit = parser.createAST(null) as CompilationUnit
+ newCompUnit
+ }
+
+ def static void testMatcher(String patternString, String sourceString, String declarationSource, Map nameBindings, Map typeBindings, Map> parameterBindings, Map visibilityBindings, Map> argumentBindings, String typeRefString) {
+ val matcher = new PatternMatcher(null)
+ val pattern = PatternParser.parse(patternString)
+ val source = TestUtils.getCompliationUnit(sourceString)
+ val matchings = if(declarationSource == "block") {
+ ((source.types.head as TypeDeclaration).bodyDeclarations.head as MethodDeclaration).body.statements
+ } else if(declarationSource == "class") {
+ (source.types.head as TypeDeclaration).bodyDeclarations
+ }
+ assertTrue(matcher.match(pattern, matchings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString))
+ }
+
+ def static testBuilder(String patternString, Map> bindings, Map nameBindings, Map typeBindings, Map> parameterBindings, Map visibilityBindings, Map> argumentBindings, String typeRefString) {
+ val builder = new ASTBuilder(null)
+ val pattern = PatternParser.parse(patternString)
+ val source = TestUtils.getCompliationUnit("")
+ builder.build(pattern, source.AST, bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+ }
+
+}
\ No newline at end of file
diff --git a/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/compiler/RefJavaCompilerTests.xtend b/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/compiler/RefJavaCompilerTests.xtend
new file mode 100644
index 0000000..b47ee03
--- /dev/null
+++ b/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/compiler/RefJavaCompilerTests.xtend
@@ -0,0 +1,297 @@
+package hu.elte.refjava.lang.tests.compiler
+
+import org.junit.jupiter.api.^extension.ExtendWith
+import org.eclipse.xtext.testing.InjectWith
+import org.eclipse.xtext.testing.extensions.InjectionExtension
+import hu.elte.refjava.lang.tests.RefJavaInjectorProvider
+import com.google.inject.Inject
+import org.eclipse.xtext.xbase.testing.CompilationTestHelper
+import org.junit.jupiter.api.Test
+
+@ExtendWith(InjectionExtension)
+@InjectWith(RefJavaInjectorProvider)
+class RefJavaCompilerTests {
+
+ @Inject extension CompilationTestHelper
+
+ @Test
+ def void compileSchemeTypes() {
+ '''
+ package file.test;
+
+ local refactoring localTest()
+ nothing
+ ~~~~~~~
+ nothing
+
+ block refactoring blockTest()
+ nothing
+ ~~~~~~~
+ nothing
+
+ lambda refactoring lambdaTest()
+ nothing
+ ~~~~~~~
+ nothing
+
+ class refactoring classTest()
+ nothing
+ ~~~~~~~
+ nothing
+ '''.assertCompilesTo('''
+ MULTIPLE FILES WERE GENERATED
+
+ File 1 : /myProject/./src-gen/file/test/blockTest.java
+
+ package file.test;
+
+ import hu.elte.refjava.api.BlockRefactoring;
+
+ @SuppressWarnings("all")
+ public class blockTest extends BlockRefactoring {
+ public blockTest() {
+ super("nothing", "nothing");
+ }
+ }
+
+ File 2 : /myProject/./src-gen/file/test/classTest.java
+
+ package file.test;
+
+ import hu.elte.refjava.api.ClassRefactoring;
+
+ @SuppressWarnings("all")
+ public class classTest extends ClassRefactoring {
+ public classTest() {
+ super("nothing", "nothing");
+ }
+ }
+
+ File 3 : /myProject/./src-gen/file/test/lambdaTest.java
+
+ package file.test;
+
+ import hu.elte.refjava.api.LambdaRefactoring;
+
+ @SuppressWarnings("all")
+ public class lambdaTest extends LambdaRefactoring {
+ public lambdaTest() {
+ super("nothing", "nothing");
+ }
+ }
+
+ File 4 : /myProject/./src-gen/file/test/localTest.java
+
+ package file.test;
+
+ import hu.elte.refjava.api.LocalRefactoring;
+
+ @SuppressWarnings("all")
+ public class localTest extends LocalRefactoring {
+ public localTest() {
+ super("nothing", "nothing");
+ }
+ }
+
+ ''')
+ }
+
+ @Test
+ def void compileSchemeWithTargetClosure() {
+ '''
+ package test;
+
+ block refactoring test()
+ nothing
+ ~~~~~~~
+ nothing
+ target
+ nothing
+ '''
+ .assertCompilesTo(
+ '''
+ package test;
+
+ import hu.elte.refjava.api.BlockRefactoring;
+
+ @SuppressWarnings("all")
+ public class test extends BlockRefactoring {
+ public test() {
+ super("nothing", "nothing");
+ }
+
+ @Override
+ protected boolean safeTargetCheck() {
+ return super.targetCheck("nothing");
+ }
+ }
+ ''')
+ }
+
+ @Test
+ def void compileSchemeWithPrecondition() {
+ '''
+ package test;
+
+ local refactoring test()
+ nothing
+ ~~~~~~~
+ nothing
+ when
+ precondition
+ isSingle(target)
+ && true == true
+ '''
+ .assertCompilesTo(
+ '''
+ package test;
+
+ import hu.elte.refjava.api.Check;
+ import hu.elte.refjava.api.LocalRefactoring;
+
+ @SuppressWarnings("all")
+ public class test extends LocalRefactoring {
+ public test() {
+ super("nothing", "nothing");
+ }
+
+ private boolean instanceCheck() {
+ return (Check.isSingle(bindings.get("target")) && (true == true));
+ }
+
+ @Override
+ protected boolean check() {
+ return super.check() && instanceCheck();
+ }
+ }
+ ''')
+ }
+
+ @Test
+ def void compileSchemeWithAssignments() {
+ '''
+ package test;
+
+ local refactoring test()
+ nothing
+ ~~~~~~~
+ nothing
+ when
+ assignment
+ name#N = "TEST" ;
+ type#T = type(target) ;
+ visibility#V = visibility(target) ;
+ parameter#P = parameters(target)
+
+ '''
+ .assertCompilesTo(
+ '''
+ package test;
+
+ import hu.elte.refjava.api.Check;
+ import hu.elte.refjava.api.LocalRefactoring;
+ import hu.elte.refjava.lang.refJava.Visibility;
+ import java.util.List;
+ import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
+ import org.eclipse.jdt.core.dom.Type;
+
+ @SuppressWarnings("all")
+ public class test extends LocalRefactoring {
+ public test() {
+ super("nothing", "nothing");
+ }
+
+ private String valueof_name_N() {
+ return "TEST";
+ }
+
+ private void set_name_N() {
+ nameBindings.put("N", valueof_name_N());
+ }
+
+ private Type valueof_type_T() {
+ Type _type = Check.type(bindings.get("target"));
+ return _type;
+ }
+
+ private void set_type_T() {
+ typeBindings.put("T", valueof_type_T());
+ }
+
+ private List valueof_visibility_V() {
+ Visibility _visibility = Check.visibility(bindings.get("target"));
+ return _visibility;
+ }
+
+ private void set_visibility_V() {
+ visibilityBindings.put("V", valueof_visibility_V());
+ }
+
+ private List valueof_parameter_P() {
+ List _parameters = Check.parameters(bindings.get("target"));
+ return _parameters;
+ }
+
+ private void set_parameter_P() {
+ parameterBindings.put("P", valueof_parameter_P());
+ }
+
+ protected void setMetaVariables() {
+ set_name_N();
+ set_type_T();
+ set_visibility_V();
+ set_parameter_P();
+
+ super.matchingTypeReferenceString = "";
+ super.replacementTypeReferenceString = "";
+ super.targetTypeReferenceString = "";
+ super.definitionTypeReferenceString = "";
+ }
+ }
+ ''')
+ }
+
+ @Test
+ def void compileSchemeWithTypeRefStrings(){
+ '''
+ package test;
+
+ class refactoring test()
+ int a ; char b ;
+ ~~~~~~~~~~~~~~
+ double c ; long d ; String e ;
+ target
+ public void f(boolean b) { }
+ definition
+ byte b ; short s ;
+
+ '''
+ .assertCompilesTo(
+ '''
+ package test;
+
+ import hu.elte.refjava.api.ClassRefactoring;
+
+ @SuppressWarnings("all")
+ public class test extends ClassRefactoring {
+ public test() {
+ super("int a ; char b ;", "double c ; long d ; String e ;");
+ }
+
+ protected void setMetaVariables() {
+ super.definitionString = "byte b ; short s ;";
+
+ super.matchingTypeReferenceString = "int|char|";
+ super.replacementTypeReferenceString = "double|long|java.lang.String|";
+ super.targetTypeReferenceString = "void|boolean|";
+ super.definitionTypeReferenceString = "byte|short|";
+ }
+
+ @Override
+ protected boolean safeTargetCheck() {
+ return super.targetCheck("public void f(boolean b) { }");
+ }
+ }
+ ''')
+ }
+}
\ No newline at end of file
diff --git a/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/parser/RefJavaParsingTests.xtend b/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/parser/RefJavaParsingTests.xtend
new file mode 100644
index 0000000..ac56b10
--- /dev/null
+++ b/hu.elte.refjava.lang.tests/src/hu/elte/refjava/lang/tests/parser/RefJavaParsingTests.xtend
@@ -0,0 +1,164 @@
+package hu.elte.refjava.lang.tests.parser
+
+import com.google.inject.Inject
+import hu.elte.refjava.lang.refJava.AssignmentList
+import hu.elte.refjava.lang.refJava.File
+import hu.elte.refjava.lang.refJava.MetaVariableType
+import hu.elte.refjava.lang.refJava.PBlockExpression
+import hu.elte.refjava.lang.refJava.PConstructorCall
+import hu.elte.refjava.lang.refJava.PExpression
+import hu.elte.refjava.lang.refJava.PFeatureCall
+import hu.elte.refjava.lang.refJava.PMemberFeatureCall
+import hu.elte.refjava.lang.refJava.PMetaVariable
+import hu.elte.refjava.lang.refJava.PMethodDeclaration
+import hu.elte.refjava.lang.refJava.PNothingExpression
+import hu.elte.refjava.lang.refJava.PReturnExpression
+import hu.elte.refjava.lang.refJava.PTargetExpression
+import hu.elte.refjava.lang.refJava.PVariableDeclaration
+import hu.elte.refjava.lang.refJava.Pattern
+import hu.elte.refjava.lang.refJava.SchemeInstanceRule
+import hu.elte.refjava.lang.refJava.SchemeType
+import hu.elte.refjava.lang.tests.RefJavaInjectorProvider
+import org.eclipse.xtext.testing.InjectWith
+import org.eclipse.xtext.testing.extensions.InjectionExtension
+import org.eclipse.xtext.testing.util.ParseHelper
+import org.eclipse.xtext.xbase.XExpression
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.^extension.ExtendWith
+
+import static org.junit.jupiter.api.Assertions.*
+
+@ExtendWith(InjectionExtension)
+@InjectWith(RefJavaInjectorProvider)
+class RefJavaParsingTests {
+
+ @Inject extension ParseHelper parseHelper
+
+ @Test
+ def void parseFile() {
+ val file = '''
+ package file.test;
+ '''.parse
+
+ assertTrue(file instanceof File)
+ assertEquals(file.name, "file.test")
+ }
+
+ @Test
+ def void parseAllSchemeTypes() {
+ val file = '''
+ package file.test;
+ local refactoring localTest()
+ nothing
+ ~~~~~~~
+ nothing
+
+ block refactoring blockTest()
+ nothing
+ ~~~~~~~
+ nothing
+
+ lambda refactoring lambdaTest()
+ nothing
+ ~~~~~~~
+ nothing
+
+ class refactoring classTest()
+ nothing
+ ~~~~~~~
+ nothing
+ '''.parse
+
+ assertTrue(file.refactorings.forall[it instanceof SchemeInstanceRule])
+ assertEquals((file.refactorings.get(0) as SchemeInstanceRule).type, SchemeType.LOCAL)
+ assertEquals((file.refactorings.get(0) as SchemeInstanceRule).name, "localTest")
+ assertEquals((file.refactorings.get(1) as SchemeInstanceRule).type, SchemeType.BLOCK)
+ assertEquals((file.refactorings.get(1) as SchemeInstanceRule).name, "blockTest")
+ assertEquals((file.refactorings.get(2) as SchemeInstanceRule).type, SchemeType.LAMBDA)
+ assertEquals((file.refactorings.get(2) as SchemeInstanceRule).name, "lambdaTest")
+ assertEquals((file.refactorings.get(3) as SchemeInstanceRule).type, SchemeType.CLASS)
+ assertEquals((file.refactorings.get(3) as SchemeInstanceRule).name, "classTest")
+ }
+
+
+ @Test
+ def void parseSchemeProperties() {
+ val file = '''
+ package file.test;
+ local refactoring test()
+ nothing
+ ~~~~~~~
+ nothing
+ target
+ nothing
+ definition
+ nothing
+ when
+ assignment
+ name#test = "TEST"
+ precondition
+ true
+ '''.parse
+
+ val refactoring = file.refactorings.head as SchemeInstanceRule
+
+ assertTrue(refactoring.matchingPattern instanceof Pattern)
+ assertTrue(refactoring.replacementPattern instanceof Pattern)
+ assertFalse(refactoring.targetPattern === null)
+ assertTrue(refactoring.targetPattern instanceof Pattern)
+ assertFalse(refactoring.definitionPattern === null)
+ assertTrue(refactoring.definitionPattern instanceof Pattern)
+ assertFalse(refactoring.assignments === null)
+ assertTrue(refactoring.assignments instanceof AssignmentList)
+ assertFalse(refactoring.precondition === null)
+ assertTrue(refactoring.precondition instanceof XExpression)
+ }
+
+ @Test
+ def void parsePatternExpressions() {
+ val file = '''
+ package file.test;
+ local refactoring test()
+ #s ; target ; return ; nothing ; { } ; public int a ; public void f() { } ; method() ; A.method() ; new F() { }
+ ~~~~~~~
+ nothing
+ '''.parse
+
+ val pattern = (file.refactorings.head as SchemeInstanceRule).matchingPattern
+ assertFalse(pattern.patterns === null)
+ assertTrue(pattern.patterns.forall[it instanceof PExpression])
+
+ val patterns = pattern.patterns
+ assertTrue(patterns.get(0) instanceof PMetaVariable)
+ assertTrue(patterns.get(1) instanceof PTargetExpression)
+ assertTrue(patterns.get(2) instanceof PReturnExpression)
+ assertTrue(patterns.get(3) instanceof PNothingExpression)
+ assertTrue(patterns.get(4) instanceof PBlockExpression)
+ assertTrue(patterns.get(5) instanceof PVariableDeclaration)
+ assertTrue(patterns.get(6) instanceof PMethodDeclaration)
+ assertTrue(patterns.get(7) instanceof PFeatureCall)
+ assertTrue(patterns.get(8) instanceof PMemberFeatureCall)
+ assertTrue(patterns.get(9) instanceof PConstructorCall)
+ }
+
+ @Test
+ def void parseMetaVariables() {
+ val file = '''
+ package file.test;
+ local refactoring test()
+ #s ; name#n ; type#t ; visibility#v ; argument#a.. ; parameter#p..
+ ~~~~~~~
+ nothing
+ '''.parse
+
+ val patterns = (file.refactorings.head as SchemeInstanceRule).matchingPattern.patterns
+ assertTrue(patterns.forall[it instanceof PMetaVariable])
+
+ assertEquals((patterns.get(0) as PMetaVariable).type, MetaVariableType.CODE)
+ assertEquals((patterns.get(1) as PMetaVariable).type, MetaVariableType.NAME)
+ assertEquals((patterns.get(2) as PMetaVariable).type, MetaVariableType.TYPE)
+ assertEquals((patterns.get(3) as PMetaVariable).type, MetaVariableType.VISIBILITY)
+ assertEquals((patterns.get(4) as PMetaVariable).type, MetaVariableType.ARGUMENT)
+ assertEquals((patterns.get(5) as PMetaVariable).type, MetaVariableType.PARAMETER)
+ }
+}
diff --git a/hu.elte.refjava.lang.ui/.classpath b/hu.elte.refjava.lang.ui/.classpath
index 8018385..bc001b4 100644
--- a/hu.elte.refjava.lang.ui/.classpath
+++ b/hu.elte.refjava.lang.ui/.classpath
@@ -1,9 +1,9 @@
+
+
-
-
diff --git a/hu.elte.refjava.lang.ui/.settings/org.eclipse.jdt.core.prefs b/hu.elte.refjava.lang.ui/.settings/org.eclipse.jdt.core.prefs
index dd5a2bb..3efb014 100644
--- a/hu.elte.refjava.lang.ui/.settings/org.eclipse.jdt.core.prefs
+++ b/hu.elte.refjava.lang.ui/.settings/org.eclipse.jdt.core.prefs
@@ -9,8 +9,8 @@ org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nul
org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=10
-org.eclipse.jdt.core.compiler.compliance=10
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.APILeak=warning
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
@@ -22,6 +22,7 @@ org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=ignore
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
@@ -67,6 +68,7 @@ org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=igno
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
@@ -105,4 +107,4 @@ org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.release=enabled
-org.eclipse.jdt.core.compiler.source=10
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/hu.elte.refjava.lang.ui/META-INF/MANIFEST.MF b/hu.elte.refjava.lang.ui/META-INF/MANIFEST.MF
index 41c2685..e054ca4 100644
--- a/hu.elte.refjava.lang.ui/META-INF/MANIFEST.MF
+++ b/hu.elte.refjava.lang.ui/META-INF/MANIFEST.MF
@@ -19,12 +19,16 @@ Require-Bundle: hu.elte.refjava,
org.eclipse.xtext.xbase.ui,
org.eclipse.compare,
org.eclipse.xtext.builder,
- org.eclipse.xtend.lib;resolution:=optional,
+ org.eclipse.xtend.lib;bundle-version="2.14.0";resolution:=optional,
org.eclipse.jdt.debug.ui
Import-Package: org.apache.log4j
-Bundle-RequiredExecutionEnvironment: JavaSE-10
-Export-Package: hu.elte.refjava.lang.ui.internal,
- hu.elte.refjava.lang.ui.quickfix,
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Export-Package: hu.elte.refjava.lang.ui,
+ hu.elte.refjava.lang.ui.contentassist,
hu.elte.refjava.lang.ui.editor,
- hu.elte.refjava.lang.ui.contentassist
+ hu.elte.refjava.lang.ui.internal,
+ hu.elte.refjava.lang.ui.labeling,
+ hu.elte.refjava.lang.ui.outline,
+ hu.elte.refjava.lang.ui.quickfix,
+ hu.elte.refjava.lang.validation
Bundle-Activator: hu.elte.refjava.lang.ui.internal.LangActivator
diff --git a/hu.elte.refjava.lang.ui/plugin.xml b/hu.elte.refjava.lang.ui/plugin.xml
index 5290adf..f9552e7 100644
--- a/hu.elte.refjava.lang.ui/plugin.xml
+++ b/hu.elte.refjava.lang.ui/plugin.xml
@@ -475,42 +475,6 @@
-
-
-
-
-
-
-
-
-
+
diff --git a/hu.elte.refjava.lang/.launch/Generate RefJava (refjava) Language Infrastructure.launch b/hu.elte.refjava.lang/.launch/Generate RefJava (refjava) Language Infrastructure.launch
index 6b8b3eb..77ba186 100644
--- a/hu.elte.refjava.lang/.launch/Generate RefJava (refjava) Language Infrastructure.launch
+++ b/hu.elte.refjava.lang/.launch/Generate RefJava (refjava) Language Infrastructure.launch
@@ -1,18 +1,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hu.elte.refjava.lang/.launch/Launch Runtime Eclipse.launch b/hu.elte.refjava.lang/.launch/Launch Runtime Eclipse.launch
index f53c414..ec3e469 100644
--- a/hu.elte.refjava.lang/.launch/Launch Runtime Eclipse.launch
+++ b/hu.elte.refjava.lang/.launch/Launch Runtime Eclipse.launch
@@ -1,35 +1,35 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hu.elte.refjava.lang/.settings/org.eclipse.jdt.core.prefs b/hu.elte.refjava.lang/.settings/org.eclipse.jdt.core.prefs
index ca12074..f1bf70b 100644
--- a/hu.elte.refjava.lang/.settings/org.eclipse.jdt.core.prefs
+++ b/hu.elte.refjava.lang/.settings/org.eclipse.jdt.core.prefs
@@ -10,9 +10,9 @@ org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=10
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=10
+org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -27,6 +27,7 @@ org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=ignore
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
@@ -72,6 +73,7 @@ org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=igno
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
@@ -110,4 +112,4 @@ org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.release=enabled
-org.eclipse.jdt.core.compiler.source=10
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/hu.elte.refjava.lang/.settings/org.eclipse.ltk.core.refactoring.prefs b/hu.elte.refjava.lang/.settings/org.eclipse.ltk.core.refactoring.prefs
new file mode 100644
index 0000000..b196c64
--- /dev/null
+++ b/hu.elte.refjava.lang/.settings/org.eclipse.ltk.core.refactoring.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
diff --git a/hu.elte.refjava.lang/META-INF/MANIFEST.MF b/hu.elte.refjava.lang/META-INF/MANIFEST.MF
index 8f5a5c7..9dd744a 100644
--- a/hu.elte.refjava.lang/META-INF/MANIFEST.MF
+++ b/hu.elte.refjava.lang/META-INF/MANIFEST.MF
@@ -12,17 +12,23 @@ Require-Bundle: org.eclipse.xtext,
org.eclipse.emf.ecore,
org.eclipse.xtext.common.types,
org.eclipse.xtext.xbase.lib;bundle-version="2.14.0",
- org.objectweb.asm;bundle-version="[6.2.1,6.3.0)";resolution:=optional,
+ org.objectweb.asm;bundle-version="[7.1.0,7.2.0)";resolution:=optional,
org.eclipse.xtext.util,
org.eclipse.emf.common,
org.eclipse.xtend.lib;bundle-version="2.14.0",
org.antlr.runtime;bundle-version="[3.2.0,3.2.1)",
org.eclipse.jdt.core;bundle-version="3.15.0",
org.eclipse.jface.text;bundle-version="3.14.0",
- org.eclipse.xtext.testing;bundle-version="2.15.0"
-Bundle-RequiredExecutionEnvironment: JavaSE-10
+ org.eclipse.xtext.testing;bundle-version="2.15.0",
+ com.google.guava,
+ org.eclipse.xtend.lib.macro,
+ org.junit,
+ org.eclipse.emf.ecore.xcore;bundle-version="1.11.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Export-Package: hu.elte.refjava.api,
+ hu.elte.refjava.api.patterns,
hu.elte.refjava.lang,
+ hu.elte.refjava.lang.compiler,
hu.elte.refjava.lang.jvmmodel,
hu.elte.refjava.lang.parser.antlr,
hu.elte.refjava.lang.parser.antlr.internal,
@@ -32,5 +38,7 @@ Export-Package: hu.elte.refjava.api,
hu.elte.refjava.lang.scoping,
hu.elte.refjava.lang.serializer,
hu.elte.refjava.lang.services,
- hu.elte.refjava.lang.validation
+ hu.elte.refjava.lang.typesystem,
+ hu.elte.refjava.lang.validation,
+ hu.elte.refjava.tests
Import-Package: org.apache.log4j
diff --git a/hu.elte.refjava.lang/plugin.xml_gen b/hu.elte.refjava.lang/plugin.xml_gen
new file mode 100644
index 0000000..4de08d7
--- /dev/null
+++ b/hu.elte.refjava.lang/plugin.xml_gen
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/api/BlockRefactoring.xtend b/hu.elte.refjava.lang/src/hu/elte/refjava/api/BlockRefactoring.xtend
new file mode 100644
index 0000000..8b001b4
--- /dev/null
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/api/BlockRefactoring.xtend
@@ -0,0 +1,161 @@
+package hu.elte.refjava.api
+
+import hu.elte.refjava.api.patterns.ASTBuilder
+import hu.elte.refjava.api.patterns.PatternMatcher
+import hu.elte.refjava.api.patterns.PatternParser
+import hu.elte.refjava.api.patterns.Utils
+import java.util.List
+import org.eclipse.jdt.core.dom.ASTNode
+import org.eclipse.jdt.core.dom.SimpleName
+import org.eclipse.jdt.core.dom.TypeDeclaration
+import org.eclipse.jface.text.IDocument
+
+class BlockRefactoring implements Refactoring {
+
+ List extends ASTNode> target
+ IDocument document
+
+ val PatternMatcher matcher
+ val ASTBuilder builder
+ protected String matchingTypeReferenceString
+ protected String replacementTypeReferenceString
+ protected String targetTypeReferenceString
+ protected String definitionTypeReferenceString
+ List replacement
+
+ protected new(String matchingPatternString, String replacementPatternString) {
+ nameBindings.clear
+ typeBindings.clear
+ parameterBindings.clear
+ visibilityBindings.clear
+ argumentBindings.clear
+ setMetaVariables
+ matcher = new PatternMatcher(PatternParser.parse(matchingPatternString))
+ builder = new ASTBuilder(PatternParser.parse(replacementPatternString))
+ }
+
+ override init(List extends ASTNode> target, IDocument document, List allTypeDeclInWorkspace) {
+ this.target = target
+ this.document = document
+ Check.allTypeDeclarationInWorkSpace = allTypeDeclInWorkspace
+ }
+
+ def setTarget(List newTarget) {
+ this.target = newTarget
+ }
+
+ override apply() {
+ return if(!safeTargetCheck) {
+ Status.TARGET_MATCH_FAILED
+ } else if (!safeMatch) {
+ Status.MATCH_FAILED
+ } else if (!safeCheck) {
+ Status.CHECK_FAILED
+ } else if (!safeBuild) {
+ Status.BUILD_FAILED
+ } else if (!safeReplace) {
+ Status.REPLACEMENT_FAILED
+ } else {
+ Status.SUCCESS
+ }
+ }
+
+ def private safeMatch() {
+ try {
+ if (!matcher.match(target, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, matchingTypeReferenceString) ) {
+ return false
+ }
+ target = matcher.modifiedTarget.toList
+ bindings.putAll(matcher.bindings)
+ true
+ } catch (Exception e) {
+ println(e)
+ false
+ }
+ }
+
+ def protected void setMetaVariables() {
+ //empty
+ }
+
+ def protected safeTargetCheck() {
+ true
+ }
+
+ def protected targetCheck(String targetPatternString) {
+ try {
+ if(!matcher.match(PatternParser.parse(targetPatternString), target, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, targetTypeReferenceString)) {
+ return false
+ }
+ bindings.putAll(matcher.bindings)
+ true
+ } catch (Exception e) {
+ println(e)
+ false
+ }
+ }
+
+ def private safeCheck() {
+ try {
+ check()
+ } catch (Exception e) {
+ println(e)
+ false
+ }
+ }
+
+ def protected check() {
+ Check.isInsideBlock(target)
+ }
+
+ def private safeBuild() {
+ try {
+ replacement = builder.build(target.head.AST, bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, replacementTypeReferenceString)
+ true
+ } catch (Exception e) {
+ println(e)
+ false
+ }
+ }
+
+ def private safeReplace() {
+ try {
+
+ val targetTypeDecl = Utils.getTypeDeclaration(target.head)
+ val assignmentBeforeReplacement = Check.getAssignmentsInClass(targetTypeDecl)
+
+ val rewrite = builder.rewrite
+ target.tail.forEach[rewrite.remove(it, null)]
+ val group = rewrite.createGroupNode(replacement)
+ rewrite.replace(target.head, group, null)
+ val edits = rewrite.rewriteAST(document, null)
+ edits.apply(document)
+
+ val iCompUnit = Utils.getICompilationUnit(target.head)
+ val compUnit = Utils.parseSourceCode(iCompUnit)
+ val assignmentsAfterReplacement = Check.getAssignmentsInClass(compUnit.types.findFirst[
+ (it as TypeDeclaration).resolveBinding.qualifiedName == targetTypeDecl.resolveBinding.qualifiedName] as TypeDeclaration)
+
+ compUnit.recordModifications
+ val it1 = assignmentBeforeReplacement.iterator
+ val it2 = assignmentsAfterReplacement.iterator
+ while (it1.hasNext) {
+ val value1 = it1.next
+ val value2 = it2.next
+ if(Check.referredField(value1.leftHandSide as SimpleName) !== null && Check.referredField(value2.leftHandSide as SimpleName) === null) {
+ val thisExpression = compUnit.AST.newThisExpression
+ val fieldAccess = compUnit.AST.newFieldAccess
+ fieldAccess.name.identifier = (value2.leftHandSide as SimpleName).identifier
+ fieldAccess.expression = thisExpression
+ value2.leftHandSide = fieldAccess
+ }
+ }
+
+ Utils.applyChanges(compUnit, document)
+ true
+ } catch (Exception e) {
+ println(e)
+ false
+ }
+ }
+}
\ No newline at end of file
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/api/Check.xtend b/hu.elte.refjava.lang/src/hu/elte/refjava/api/Check.xtend
index 32e2f9f..169e639 100644
--- a/hu.elte.refjava.lang/src/hu/elte/refjava/api/Check.xtend
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/api/Check.xtend
@@ -1,34 +1,98 @@
package hu.elte.refjava.api
+import hu.elte.refjava.api.patterns.Utils
+import hu.elte.refjava.lang.refJava.Visibility
+import java.lang.reflect.Modifier
import java.util.List
+import java.util.Queue
import org.eclipse.jdt.core.dom.ASTNode
import org.eclipse.jdt.core.dom.ASTVisitor
+import org.eclipse.jdt.core.dom.AnonymousClassDeclaration
+import org.eclipse.jdt.core.dom.ArrayType
+import org.eclipse.jdt.core.dom.Assignment
import org.eclipse.jdt.core.dom.Block
+import org.eclipse.jdt.core.dom.ClassInstanceCreation
+import org.eclipse.jdt.core.dom.ExpressionStatement
+import org.eclipse.jdt.core.dom.FieldDeclaration
+import org.eclipse.jdt.core.dom.ITypeBinding
+import org.eclipse.jdt.core.dom.MethodDeclaration
+import org.eclipse.jdt.core.dom.MethodInvocation
+import org.eclipse.jdt.core.dom.Name
+import org.eclipse.jdt.core.dom.QualifiedName
+import org.eclipse.jdt.core.dom.ReturnStatement
import org.eclipse.jdt.core.dom.SimpleName
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration
import org.eclipse.jdt.core.dom.Statement
+import org.eclipse.jdt.core.dom.Type
+import org.eclipse.jdt.core.dom.TypeDeclaration
import org.eclipse.jdt.core.dom.VariableDeclarationFragment
import org.eclipse.jdt.core.dom.VariableDeclarationStatement
class Check {
+ protected static List allTypeDeclarationInWorkSpace
+
+ /////////////////
+ //public checks//
+ /////////////////
+
+ /**
+ * Determines whether the given list of ASTNodes consist of one element.
+ * @param target the list of ASTNodes
+ * @return true, if target consist of on element, false otherwise
+ */
+ def static isSingle(List extends ASTNode> target) {
+ target.size == 1
+ }
+
+ /**
+ * Determines whether the given ASTNode is located inside a Block.
+ * @param node the ASTnode
+ * @return true, if node located inside a Block, false otherwise
+ */
def static isInsideBlock(ASTNode node) {
node.parent instanceof Block
}
-
+
+ /**
+ * Determines whether the all of the given list of ASTNodes' element is located in a Block.
+ * @param nodes the list of ASTNodes
+ * @return true, if all of node's element located inside a Block, false otherwise
+ */
def static isInsideBlock(List extends ASTNode> nodes) {
nodes.forall[isInsideBlock]
}
- def static isVariableDeclaration(ASTNode node) {
+ /**
+ * Determines whether the given ASTNode is a variable declaration.
+ * @param node the list of ASTNodes
+ * @return true, if node is a variable declaration, false otherwise
+ */
+ def dispatch static isVariableDeclaration(ASTNode node) {
node instanceof VariableDeclarationStatement
}
+
+ /**
+ * Determines whether the all of the given list of ASTNodes' element is a variable declaration.
+ * @param node the list of ASTNodes
+ * @return true, if all of nodes' element is a variable declaration, false otherwise
+ */
+ def dispatch static isVariableDeclaration(List nodes) {
+ nodes.forall[it instanceof VariableDeclarationStatement]
+ }
- def static asVariableDeclaration(ASTNode node) {
+ def dispatch static asVariableDeclaration(ASTNode node) {
if (node instanceof VariableDeclarationStatement) {
node
}
}
+ def dispatch static asVariableDeclaration(List nodes) {
+ if (nodes.isVariableDeclaration) {
+ nodes as List
+ }
+ }
+
def static blockRemainder(ASTNode node) {
val parent = node.parent
if (parent instanceof Block) {
@@ -36,7 +100,7 @@ class Check {
}
}
- def static isReferencedIn(VariableDeclarationStatement varDecl, List extends ASTNode> nodes) {
+ def dispatch static isReferencedIn(VariableDeclarationStatement varDecl, List extends ASTNode> nodes) {
(varDecl.fragments as List).exists [
val varBinding = resolveBinding
nodes.exists [
@@ -48,15 +112,1081 @@ class Check {
found = true
return false
}
-
return true
}
}
-
accept(visitor)
return visitor.found
]
]
}
+
+ def dispatch static boolean isReferencedIn(List varDeclList, List extends ASTNode> nodes) {
+ varDeclList.exists[it.isReferencedIn(nodes)]
+ }
+
+
+ //OPTIONAL CHECK
+ //determines whether the selected nodes contains a ReturnExpression with an expression that is not null
+ def static containsValueReturn(List extends ASTNode> target) {
+ target.exists [
+ val visitor = new ASTVisitor() {
+ public var found = false
+ override visit(ReturnStatement statement) {
+ if (statement.expression !== null) {
+ found = true
+ return false
+ }
+ true
+ }
+ }
+ it.accept(visitor)
+ visitor.found
+ ]
+ }
+
+
+ //OPTIONAL CHECK
+ //determines whether the selected nodes contains a ReturnExpression with an expression that is null
+ def static containsVoidReturn(List extends ASTNode> target) {
+ target.exists [
+ val visitor = new ASTVisitor() {
+ public var found = false
+ override visit(ReturnStatement statement) {
+ if (statement.expression === null) {
+ found = true
+ return false
+ }
+ true
+ }
+ }
+ it.accept(visitor)
+ visitor.found
+ ]
+ }
+
+ //OPTIONAL CHECK
+ //gets the first ReturnExpression which expression is null from the selected nodes.. returns null if such a node doesn't exists
+ def static getVoidReturn(List extends ASTNode> target) {
+ val List result = newArrayList
+ target.exists [
+ val visitor = new ASTVisitor() {
+ public var found = false
+ override visit(ReturnStatement statement) {
+ if (statement.expression === null) {
+ found = true
+ result.add(statement)
+ return false
+ }
+ true
+ }
+ }
+ it.accept(visitor)
+ visitor.found
+ ]
+ result.head as ReturnStatement
+ }
+
+ /**
+ * Determines whether if the a ReturnStatement is the last possible execution node of the Block which has the statement.
+ * @param statement the ReturnStatement
+ * @return true, if its the last execution path, false otherwise
+ */
+ def static isLastExecutionNode(ReturnStatement statement) {
+ var firstLevelNodeInMethod = statement as ASTNode
+ while (!((firstLevelNodeInMethod.parent instanceof Block) && ((firstLevelNodeInMethod.parent as Block).parent instanceof MethodDeclaration))) {
+ firstLevelNodeInMethod = firstLevelNodeInMethod.parent
+ }
+ val node = firstLevelNodeInMethod
+ val nodesAfterReturnStatement = (firstLevelNodeInMethod.parent as Block).statements.dropWhile[it != node]
+ nodesAfterReturnStatement.size == 1 && nodesAfterReturnStatement.head == node
+ }
+
+ /**
+ * Gets the identifier of the first element of the given list of ASTNodes.
+ * Note: Only works if the first element of the given list is a MethodDeclaration. Returns null otherwise.
+ * @param target the list of ASTNodes
+ * @return the identifier of target's first element
+ */
+ def static String getMethodName(List extends ASTNode> target) {
+ if (target.head instanceof MethodDeclaration) {
+ return (target.head as MethodDeclaration).name.identifier
+ }
+ null
+ }
+
+ /**
+ * Gets the identifiers of the first element of the given list of ASTNodes.
+ * Note: Only works if the first element of the given list is a FieldDeclaration. Returns null otherwise.
+ * @param target the list of ASTNodes
+ * @return the list of identifiers of target's first element
+ */
+ def static getFragmentNames(List extends ASTNode> target) {
+ if(target.head instanceof FieldDeclaration) {
+ val fragments = (target.head as FieldDeclaration).fragments as List
+ var List fragmentNames = newArrayList
+ for(fragment : fragments) {
+ fragmentNames.add(fragment.name.identifier)
+ }
+ return fragmentNames
+ }
+ null
+ }
+
+ /**
+ * Gets the type of a list of ASTNodes' first element.
+ * Note: Only works if the first element of the given list is either a FieldDeclaration, or a MethodDeclaration. Returns null otherwise.
+ * @param target the list of ASTNodes
+ * @return the type or return type of target's first element (org.eclipse.jdt.core.dom.Type)
+ */
+ def dispatch static Type type(List extends ASTNode> target) {
+ if (target.head instanceof MethodDeclaration) {
+ return type(target.head)
+ } else if (target.head instanceof FieldDeclaration) {
+ return type(target.head)
+ }
+ null
+ }
+
+ /**
+ * Gets the visibility of a list of ASTNodes' first element.
+ * Note: Only works if the first element of the given list is either a FieldDeclaration, or a MethodDeclaration. Returns null otherwise.
+ * @param target the list of ASTNodes
+ * @return the visibility of target's first element (hu.elte.refjava.lang.refJava.Visibility)
+ */
+ def dispatch static Visibility visibility(List extends ASTNode> target) {
+ if(target.head instanceof MethodDeclaration) {
+ return visibility(target.head as MethodDeclaration)
+ } else if (target.head instanceof FieldDeclaration) {
+ return visibility(target.head as FieldDeclaration)
+ }
+ null
+ }
+
+ /**
+ * Gets the parameters of a list of ASTNodes' first element.
+ * Note: Only works if the first element of the given list is a MethodDeclaration. Returns null otherwise.
+ * @param target the list of ASTNodes
+ * @return the parameters of target's first element (list of org.eclipse.jdt.core.dom.SingleVariableDeclaration)
+ */
+ def dispatch static parameters(List extends ASTNode> target) {
+ if(target.head instanceof MethodDeclaration) {
+ return (target.head as MethodDeclaration).parameters as List
+ }
+ null
+ }
+
+ /**
+ * Gets the class of a list of ASTNode's first element.
+ * Note: The the returned class will be on the same AST as the given list of ASTNodes' first element.
+ * @param target the list of ASTNodes
+ * @return the class of target's first element (org.eclipse.jdt.core.dom.TypeDeclaration)
+ */
+ def static enclosingClass(List extends ASTNode> target) {
+ Utils.getTypeDeclaration(target.head)
+ }
+
+ /**
+ * Generates a fresh TypeDeclaration identifier in the workspace.
+ * @return the newly generated identifier
+ */
+ def static generateNewName() {
+ var int i = 1
+ var newName = "newLambda"
+ while(!isFresh(newName)) {
+ newName = "newLambda" + i++
+ }
+ newName
+ }
+
+ /**
+ * Determines if an identifier is used in the workspace as a TypeDeclaration identifier.
+ * @param name the identifier
+ * @return true, if identifier isn't used, false otherwise
+ */
+ def static isFresh(String name) {
+ !allTypeDeclarationInWorkSpace.exists[it.name.identifier == name]
+ }
+
+ /**
+ * Gets all references to a MethodDeclartion that can get accessed via public interface.
+ * @param methodName the MethodDeclaration's name
+ * @param methodParameters the MethodDeclaration's parameters
+ * @param targetTypeDeclaration the MethodDeclaration's TypeDeclaration
+ * @return list of ASTNodes
+ */
+ def protected static publicReferences(String methodName, List methodParameters, TypeDeclaration targetTypeDeclaration) {
+ references("public", methodName, methodParameters, targetTypeDeclaration)
+ }
+
+ /**
+ * Gets all references to a FieldDeclaration that can get accessed via public interface.
+ * @param fragmentNames the FieldDeclaration's fragment names
+ * @param targetTypeDeclaration the FieldDeclaration's TypeDeclaration
+ * @return list of ASTNodes
+ */
+ def protected static publicReferences(List fragmentNames, TypeDeclaration targetTypeDecl) {
+ references("public", fragmentNames, targetTypeDecl)
+ }
+
+ ////////////////////////////
+ //private/protected checks//
+ ////////////////////////////
+
+ /**
+ * Gets all Assignments from a TypeDeclareation.
+ * @param typeDecl the target TypeDeclaration
+ * @return all Assignments in the target TypeDeclaration
+ */
+ def protected static getAssignmentsInClass(TypeDeclaration typeDecl) {
+ val List assignments = newArrayList
+ val visitor = new ASTVisitor() {
+ override visit(Assignment assignment) {
+ if (assignment.leftHandSide instanceof SimpleName) {
+ assignments.add(assignment)
+ }
+ return true
+ }
+ }
+ typeDecl.accept(visitor)
+ assignments
+ }
+
+ //gets all references to a TypeDeclaration in the workspace, except the TypeDeclaration itself
+ //TODO
+ def protected static references(TypeDeclaration typeDecl) {
+ val List references = newArrayList
+ val binding = typeDecl.name.resolveBinding
+ allTypeDeclarationInWorkSpace.forEach[
+ val visitor = new ASTVisitor() {
+ override visit(SimpleName name) {
+ if (name.resolveBinding.isEqualTo(binding) && name != typeDecl.name) {
+ references.add(name)
+ }
+ true
+ }
+ }
+ it.accept(visitor)
+ ]
+ references
+ }
+
+ /**
+ * //TODO
+ * @param references
+ * @param target
+ * @return
+ */
+ def protected static contains(List references, List extends ASTNode> target) {
+ if(target.head instanceof ExpressionStatement &&
+ (target.head as ExpressionStatement).expression instanceof MethodInvocation &&
+ ((target.head as ExpressionStatement).expression as MethodInvocation).expression instanceof ClassInstanceCreation &&
+ (((target.head as ExpressionStatement).expression as MethodInvocation).expression as ClassInstanceCreation).anonymousClassDeclaration !== null ) {
+
+ for(refs : references) {
+ if( (refs as SimpleName).resolveBinding.isEqualTo( (((target.head as ExpressionStatement).expression as MethodInvocation).expression as ClassInstanceCreation).type.resolveBinding) ) {
+ return true
+ }
+ }
+ }
+ false
+ }
+
+ /**
+ * Gets the type identifier of a ClassInstanceCreation (lambda expression's expression).
+ * @param exprStatement the lambda expression (as an ExpressionStatement, which has a MethodInvocation expression)
+ * @return the lambda expression's identifier
+ */
+ def protected static getLambdaName(ExpressionStatement exprStatement) {
+ ((exprStatement.expression as MethodInvocation).expression as ClassInstanceCreation).type.toString
+ }
+
+ /**
+ * Gets a ClassInstanceCreation's anonymous class declaration.
+ * @param exprStatement the lambda expression (as an ExpressionStatement, which has a MethodInvocation expression)
+ * @return the lambda expression's body
+ */
+ def protected static getLambdaBody(ExpressionStatement exprStatement) {
+ ((exprStatement.expression as MethodInvocation).expression as ClassInstanceCreation).anonymousClassDeclaration
+ }
+
+ /**
+ * Gets all Assignments from an anonymous class declaration.
+ * @param anonClass the AnonymousClassDeclaration
+ * @return all Assignments from the given AnonymousClassDeclaration
+ */
+ def protected static lambdaVariableAssignments(AnonymousClassDeclaration anonClass) {
+ val List variableWrites = newArrayList
+ anonClass.bodyDeclarations.forEach [
+ val visitor = new ASTVisitor() {
+ override visit(Assignment assignment) {
+ variableWrites.add(assignment)
+ }
+ }
+ (it as ASTNode).accept(visitor)
+ ]
+ variableWrites
+ }
+
+ /**
+ * Determines whether an Assignment's left hand side is declared in the given AnonymousClassDeclaration
+ * @param assignment the Assignment
+ * @param anonClass the AnonymousClassDeclaration
+ * @return true, if assignment's left hand side declared in anonClass
+ */
+ def protected static isDeclaredIn(Assignment assignment, AnonymousClassDeclaration anonClass) {
+ if(assignment.leftHandSide instanceof SimpleName) {
+ val varName = (assignment.leftHandSide as SimpleName)
+ val List namesList = newArrayList
+ anonClass.bodyDeclarations.forEach[
+ val visitor = new ASTVisitor() {
+ override visit(SimpleName name) {
+ if(name.identifier == varName.identifier) {
+ namesList.add(name)
+ return true
+ }
+ true
+ }
+ }
+ (it as ASTNode).accept(visitor)
+ ]
+ for (name : namesList) {
+ if (name == varName) {
+ return false
+ } else if (name.parent instanceof VariableDeclarationFragment) {
+ return true
+ }
+ }
+ return false
+ }
+ true
+ }
+
+ /**
+ * Gets the return type of a MethodDeclaration.
+ * @param methodDecl the MethodDeclaration
+ * @return the return type of the given MethodDeclaration (org.eclipse.jdt.core.dom.Type)
+ */
+ def protected dispatch static type(MethodDeclaration methodDecl) {
+ methodDecl.returnType2
+ }
+
+ /**
+ * Gets the type of a FieldDeclaration.
+ * @param fieldDecl the FieldDeclaration
+ * @return the type of the given FieldDeclaration (org.eclipse.jdt.core.dom.Type)
+ */
+ def protected dispatch static type(FieldDeclaration fieldDecl) {
+ fieldDecl.type
+ }
+
+ /**
+ * Gets the visibility of a FieldDeclaration.
+ * @param fieldDecl the FieldDeclaration
+ * @return the visibility of the given FieldDeclaration (hu.elte.refjava.lang.refJava.Visibility)
+ */
+ def protected dispatch static visibility(FieldDeclaration fieldDecl) {
+ val modifiers = fieldDecl.getModifiers
+ switch modifiers {
+ case modifiers.bitwiseAnd(Modifier.PUBLIC) > 0 : Visibility.PUBLIC
+ case modifiers.bitwiseAnd(Modifier.PRIVATE) > 0 : Visibility.PRIVATE
+ case modifiers.bitwiseAnd(Modifier.PROTECTED) > 0 : Visibility.PROTECTED
+ case modifiers.bitwiseAnd(Modifier.PROTECTED) == 0 && modifiers.bitwiseAnd(Modifier.PRIVATE) == 0 && modifiers.bitwiseAnd(Modifier.PUBLIC) == 0 : Visibility.PACKAGE
+ }
+ }
+
+ /**
+ * Gets the visibility of a MethodDeclaration.
+ * @param methodDecl the MethodDeclaration
+ * @return the visibility of the given MethodDeclaration (hu.elte.refjava.lang.refJava.Visibility)
+ */
+ def protected dispatch static visibility(MethodDeclaration methodDecl) {
+ val modifiers = methodDecl.getModifiers
+ switch modifiers {
+ case modifiers.bitwiseAnd(Modifier.PUBLIC) > 0 : Visibility.PUBLIC
+ case modifiers.bitwiseAnd(Modifier.PRIVATE) > 0 : Visibility.PRIVATE
+ case modifiers.bitwiseAnd(Modifier.PROTECTED) > 0 : Visibility.PROTECTED
+ case modifiers.bitwiseAnd(Modifier.PROTECTED) == 0 && modifiers.bitwiseAnd(Modifier.PRIVATE) == 0 && modifiers.bitwiseAnd(Modifier.PUBLIC) == 0 : Visibility.PACKAGE
+ }
+ }
+
+ /**
+ * Gets the parameters of a MethodDeclaration.
+ * @param methodDecl the MethodDeclaration
+ * @return the parameters of the given MethodDeclaration (list of org.eclipse.jdt.core.dom.SingleVariableDeclaration)
+ */
+ def protected dispatch static parameters(MethodDeclaration methodDecl) {
+ methodDecl.parameters as List
+ }
+
+ /**
+ * Gets the superclass of a TypeDeclaration.
+ * Note: Only works if the given TypeDeclaration has a superclass. Also, the returned superclass will be on an another AST.
+ * @param typeDecl the TypeDeclaration
+ * @return typeDecl's superclass (org.eclipse.jdt.core.dom.TypeDeclaration)
+ */
+ def protected static superClass(TypeDeclaration typeDecl) {
+ allTypeDeclarationInWorkSpace.findFirst[it.resolveBinding.qualifiedName == typeDecl.superclassType.resolveBinding.qualifiedName]
+ }
+
+
+ /**
+ * Determines whether a TypeDeclaration has a superclass.
+ * @param typeDecl the TypeDeclaration
+ * @return true, if typeDecl has a superclass, false otherwise
+ */
+ def protected static hasSuperClass(TypeDeclaration typeDecl) {
+ return typeDecl.superclassType !== null
+ }
+
+ /**
+ * Determines whether a list of ASTNode's first element's visibility is 'private'.
+ * Note: Only works if the given list of ASTNodes' first element if either a FieldDeclaration, or a MethodDeclaration. Returns false otherwise.
+ * @param target the list of ASTNodes
+ * @return true, if target's first element's visibility if 'private', false otherwise
+ */
+ def protected static isPrivate(List extends ASTNode> target) {
+ if (target.head instanceof FieldDeclaration) {
+ return Modifier.isPrivate( (target.head as FieldDeclaration).getModifiers())
+ } else if(target.head instanceof MethodDeclaration) {
+ return Modifier.isPrivate( (target.head as MethodDeclaration).getModifiers())
+ }
+ false
+ }
+
+ /**
+ * Gets all the references from a TypeDeclarations to the first element given list of ASTNodes.
+ * Note: Only works if the first element of the given list is either a FieldDeclaration, or a MethodDeclaration. Returns an empty list otherwise.
+ * @param target the list of ASTNodes
+ * @param typeDecl the TypeDeclaration
+ * @return the references to the first element of target
+ */
+ def protected static references(List target, TypeDeclaration typeDecl) {
+ val bodyDeclarations = typeDecl.bodyDeclarations
+ val List refs = newArrayList
+
+ if (target.head instanceof FieldDeclaration) {
+ val fieldDecl = target.head as FieldDeclaration
+ val fragments = fieldDecl.fragments as List
+ for(fragment : fragments) {
+ val binding = fragment.resolveBinding
+ for(declaration : bodyDeclarations) {
+ val visitor = new ASTVisitor() {
+ override visit(SimpleName name) {
+ if (name.resolveBinding.isEqualTo(binding) && name != fragment.name) {
+ refs.add(name)
+ }
+ return true
+ }
+ }
+ (declaration as ASTNode).accept(visitor)
+ }
+ }
+ } else if (target.head instanceof MethodDeclaration) {
+ val methodDecl = target.head as MethodDeclaration
+ val binding = methodDecl.resolveBinding
+ for(declaration : bodyDeclarations) {
+ val visitor = new ASTVisitor() {
+ override visit(SimpleName name) {
+ if (name.resolveBinding.isEqualTo(binding) && name != methodDecl.name) {
+ refs.add(name)
+ }
+ return true
+ }
+ }
+ (declaration as ASTNode).accept(visitor)
+ }
+ }
+ refs
+ }
+
+ /**
+ * Determines whether a given identifier is used as a FieldDeclaration's identifier in a TypeDeclaration.
+ * @param fragmentName the identifier
+ * @param typeDecl the TypeDeclaration
+ * @return true, if fragmentName isn't used as an identifier , false otherwise
+ */
+ def private static isUniqueFieldIn(String fragmentName, TypeDeclaration typeDecl) {
+ typeDecl.bodyDeclarations.filter[it instanceof FieldDeclaration].forall[
+ !((it as FieldDeclaration).fragments as List).exists[
+ it.name.identifier == fragmentName
+ ]
+ ]
+ }
+
+ /**
+ * Determines whether neither of the given identifiers is used as a FieldDeclaration's identifier in a TypeDeclaration.
+ * @param fragmentNames the list of identifiers
+ * @param typeDecl the TypeDeclaration
+ * @return true, if none of fragmentNames used as an identifier , false otherwise
+ */
+ def protected static isUniqueFieldIn(List fragmentNames, TypeDeclaration typeDecl) {
+ fragmentNames.forall[
+ isUniqueFieldIn(it, typeDecl)
+ ]
+ }
+
+ /**
+ * Determines whether if a method exists with the same name and parameter types as the given name and parameter types in a TypeDeclaration.
+ * @param methodName the method's name
+ * @param parameters the method's parameters
+ * @param typeDecl the TypeDeclaration
+ * @return true, if there isn't a method with the same name and parameter, false otherwise
+ */
+ def protected static isUniqueMethodIn(String methodName, List parameters, TypeDeclaration typeDecl) {
+ val methodsInClass = typeDecl.bodyDeclarations.filter[it instanceof MethodDeclaration]
+
+ for (method : methodsInClass) {
+ if ((method as MethodDeclaration).name.identifier == methodName && parameters.size == ((method as MethodDeclaration).parameters.size)) {
+ if (parameters.size == 0) {
+ return false
+ }
+
+ val it1 = parameters.iterator
+ val it2 = ((method as MethodDeclaration).parameters as List).iterator
+ var boolean l = true
+ while(it1.hasNext && l) {
+ l = it1.next.type.toString == it2.next.type.toString
+ }
+
+ if (l) {
+ return false
+ }
+ }
+ }
+ true
+ }
+
+ /**
+ * Gets all the FielDeclaration that have a reference inside the first element of the given list of ASTNodes' body, in a TypeDeclaration.
+ * Note: Only works if the fist element of the given list is a MethodDeclaration. Returns an empty list otherwise.
+ * @param target the list of ASTNodes
+ * @param typeDecl the TypeDeclaration
+ * @return the referenced FieldDeclarations
+ */
+ def protected static accessedFieldsOfEnclosingClass(List extends ASTNode> target, TypeDeclaration typeDecl) {
+ val methodDecl = target.head as MethodDeclaration
+
+ val List accessedFields = newArrayList
+ val methodBody = methodDecl.body
+ val classFields = typeDecl.bodyDeclarations.filter[it instanceof FieldDeclaration]
+ for (field : classFields) {
+ val fragments = (field as FieldDeclaration).fragments as List
+ for(fragment : fragments) {
+ val binding = fragment.resolveBinding
+ methodBody.statements.exists[
+ val visitor = new ASTVisitor() {
+ public var found = false
+
+ override visit(SimpleName name) {
+ if(name.resolveBinding.isEqualTo(binding)) {
+ found = true
+ return false
+ }
+ return true
+ }
+ }
+ (it as ASTNode).accept(visitor)
+ if(visitor.found) {
+ accessedFields.add(field as ASTNode)
+ }
+ return visitor.found
+ ]
+ }
+ }
+ accessedFields
+ }
+
+ /**
+ * Gets all the MethodDeclarations that have a reference inside the first element of the given list of ASTNodes' body, in a TypeDeclaration.
+ * Note: Only works if the fist element of the given list is a MethodDeclaration. Returns an empty list otherwise.
+ * @param target the list of ASTNodes
+ * @param typeDecl the TypeDeclaration
+ * @return the referenced MethodDeclarations
+ */
+ def protected static accessedMethodsOfEnclosingClass(List extends ASTNode> target, TypeDeclaration typeDecl) {
+ val methodDecl = target.head as MethodDeclaration
+
+ val List accessedMethods = newArrayList
+ val methodBody = methodDecl.body
+ val classMethods = typeDecl.bodyDeclarations.filter[it instanceof MethodDeclaration]
+ for (method : classMethods) {
+ val binding = (method as MethodDeclaration).resolveBinding
+ methodBody.statements.exists[
+ val visitor = new ASTVisitor() {
+ public var found = false
+
+ override visit(SimpleName name) {
+ if(name.resolveBinding.isEqualTo(binding) && name != methodDecl.name) {
+ found = true
+ return false
+ }
+ return true
+ }
+ }
+ (it as ASTNode).accept(visitor)
+ if(visitor.found) {
+ accessedMethods.add(method as ASTNode)
+ }
+ return visitor.found
+ ]
+ }
+ accessedMethods
+ }
+
+ /**
+ * Determines whether if a method exists with the same name and parameter types as the given name and parameter types in a one of the given TypeDeclaration's superclass.
+ * @param methodName the method's name
+ * @param parameters the method's parameters
+ * @param typeDecl the TypeDeclaration
+ * @return true, if there isn't a method with the same name and parameter, false otherwise
+ */
+ def protected static isOverrideIn(String methodName, List parameters, TypeDeclaration typeDecl){
+ var superClassToCheck = typeDecl
+ var found = false
+
+ while (superClassToCheck.hasSuperClass && !found) {
+ superClassToCheck = superClassToCheck.superClass
+ found = !isUniqueMethodIn(methodName, parameters, superClassToCheck) && !Modifier.isPrivate(getMethodFromClass(methodName, parameters, superClassToCheck).getModifiers)
+ }
+ found
+ }
+
+ /**
+ * Gets the method with the same name and parameter types as the given name and parameter types from a first of the given TypeDeclaration's superclass, that has one.
+ * Note: Only works if such a method exists.
+ * @param methodName the method's name
+ * @param parameters the method's parameters
+ * @param typeDecl the TypeDeclaration
+ * @return the method with the same name and parameter types
+ */
+ def protected static overridenMethodFrom(String methodName, List parameters, TypeDeclaration typeDecl) {
+ var superClassToCheck = typeDecl
+ var found = false
+ var MethodDeclaration method
+ while (superClassToCheck.hasSuperClass && !found) {
+ superClassToCheck = superClassToCheck.superClass
+ if(!isUniqueMethodIn(methodName, parameters, superClassToCheck)) {
+ found = true
+ method = getMethodFromClass(methodName, parameters, superClassToCheck)
+ }
+ }
+ method
+ }
+
+ /**
+ * Gets the FieldDeclaration from a TypeDeclaration with the given list of identifiers.
+ * @param fragmentNames the list of identifiers
+ * @param typeDecl the TypeDeclaration
+ * @return the FieldDeclaration with the given list of identifiers
+ */
+ def protected static getFieldFromClass(List fragmentNames, TypeDeclaration typeDecl) {
+ typeDecl.bodyDeclarations.findFirst[
+ val iter = fragmentNames.iterator
+ it instanceof FieldDeclaration && ((it as FieldDeclaration).fragments as List).forall[
+ if (iter.hasNext){
+ it.name.identifier == iter.next
+ } else {
+ false
+ }
+ ]
+ ] as FieldDeclaration
+ }
+
+ /**
+ * Gets the MethodDeclaration from a TypeDeclaration with the given name and parameter types.
+ * @param methodName the visibility to be examined
+ * @param parameters the visibility that targetVisibility will be compared to
+ * @param typeDecl the TypeDeclaration
+ * @return the MethodDeclaration with the given name and parameter types
+ */
+ def protected static getMethodFromClass(String methodName, List parameters, TypeDeclaration typeDecl) {
+ val methodsInClass = typeDecl.bodyDeclarations.filter[it instanceof MethodDeclaration]
+ var MethodDeclaration result
+ for(method : methodsInClass) {
+ if ((method as MethodDeclaration).name.identifier == methodName && parameters.size == ((method as MethodDeclaration).parameters.size)) {
+ if(parameters.size == 0) {
+ result = method as MethodDeclaration
+ }
+
+ val it1 = parameters.iterator
+ val it2 = ((method as MethodDeclaration).parameters as List).iterator
+ var boolean l = true
+ while(it1.hasNext && l) {
+ l = it1.next.type.toString == it2.next.type.toString
+ }
+
+ if (l) {
+ result = method as MethodDeclaration
+ }
+ }
+ }
+ result
+ }
+
+ /**
+ * Determines whether targetVisibility is less visible than actualVisibility
+ * @param targetVisibility the visibility to be examined
+ * @param actualVisibility the visibility that targetVisibility will be compared to
+ * @return true, if targetVisibility is less visible than actualVisibility, false otherwise
+ */
+ def protected static isLessVisible(Visibility targetVisibility, Visibility actualVisibility) {
+ if ((actualVisibility == Visibility.PUBLIC && (targetVisibility == Visibility.PRIVATE || targetVisibility == Visibility.PACKAGE || targetVisibility == Visibility.PROTECTED)) ||
+ actualVisibility == Visibility.PROTECTED && (targetVisibility == Visibility.PRIVATE || targetVisibility == Visibility.PACKAGE) ||
+ actualVisibility == Visibility.PACKAGE && (targetVisibility == Visibility.PRIVATE) ) {
+ true
+ } else {
+ false
+ }
+ }
+
+ /**
+ * Determines whether targetType is a subclass of actualType. Both are ITypeBindings.
+ * @param targetType the targetType to be examined
+ * @param actualType the type that targetType will be compared to
+ * @return true, if targetType is a subclass of actualType, false otherwise
+ */
+ def private static isSubClassOf(ITypeBinding targetType, ITypeBinding actualType) {
+ var tmp = targetType
+ var boolean l = targetType.isEqualTo(actualType)
+ while (tmp.superclass !== null && !l) {
+ tmp = tmp.superclass
+ l = tmp.isEqualTo(actualType)
+ }
+ return l
+ }
+
+ /**
+ * Determines whether targetType is a subtype of actualType. Both are org.eclipse.jdt.core.dom.Type.
+ * @param targetType the targetType to be examined
+ * @param actualType the type that targetType will be compared to
+ * @return true, if targetType is a subtype of actualType, false otherwise
+ */
+ def protected static isSubTypeOf(Type targetType, Type actualType) {
+ if (targetType.isPrimitiveType && actualType.isPrimitiveType) {
+ targetType.toString == actualType.toString
+ } else if (targetType.arrayType && actualType.arrayType) {
+ if ((targetType as ArrayType).getDimensions != (actualType as ArrayType).getDimensions ) {
+ false
+ } else {
+ if((targetType as ArrayType).elementType.isPrimitiveType && (actualType as ArrayType).elementType.isPrimitiveType) {
+ (targetType as ArrayType).elementType.toString == (actualType as ArrayType).elementType.toString
+ } else {
+ targetType.resolveBinding.isSubClassOf(actualType.resolveBinding)
+ }
+ }
+ } else if (targetType.simpleType && actualType.simpleType) {
+ targetType.resolveBinding.isSubClassOf(actualType.resolveBinding)
+ } else {
+ false
+ }
+ }
+
+ /**
+ *
+ * @param name
+ * @param typeDecl
+ * @return
+ */
+ def private static getTypeOfFieldOrVarDeclOfName(Name name, TypeDeclaration typeDecl) {
+ val binding = if (name instanceof QualifiedName) {
+ name.qualifier.resolveBinding
+ } else if (name instanceof SimpleName) {
+ name.resolveBinding
+ }
+
+ val List result = newArrayList
+ typeDecl.bodyDeclarations.exists[
+ val visitor = new ASTVisitor() {
+ public var boolean found = false
+
+ override visit(SimpleName name) {
+ if(name.resolveBinding.isEqualTo(binding) && (Utils.getFieldDeclaration(name) !== null || Utils.getVariableDeclaration(name) !== null) ) {
+ found = true
+ if(Utils.getFieldDeclaration(name) !== null) {
+ result.add(Utils.getFieldDeclaration(name))
+ } else {
+ result.add(Utils.getVariableDeclaration(name))
+ }
+ return false
+ }
+ return true
+ }
+ }
+ (it as ASTNode).accept(visitor)
+ return visitor.found
+ ]
+
+ if(!result.empty && result.get(0) instanceof FieldDeclaration) {
+ return (result.get(0) as FieldDeclaration).type
+ } else if (!result.empty && result.get(0) instanceof VariableDeclarationStatement) {
+ return (result.get(0) as VariableDeclarationStatement).type
+ }
+ }
+
+ /**
+ * Gets the field the is referred by an ASTNode.
+ * Note: Only works if the reference is a SimpleName, and referring to a Field. Returns null otherwise.
+ * @param reference the ASTNode
+ * @return the referred FieldDeclaration
+ */
+ def protected static referredField(ASTNode reference) {
+ if(reference instanceof SimpleName) {
+ val binding = (reference as SimpleName).resolveBinding
+ for(typeDecl : allTypeDeclarationInWorkSpace) {
+ for (declaration : typeDecl.bodyDeclarations) {
+ if(declaration instanceof FieldDeclaration && ((declaration as FieldDeclaration).fragments as List).exists[it.resolveBinding.isEqualTo(binding)] ) {
+ return declaration as FieldDeclaration
+ }
+ }
+ }
+ }
+ null
+ }
+
+ /**
+ * Gets all references to a FieldDeclaration in one of the given TypeDeclaration's superclass, that can potentially get violated of it gets overridden.
+ * @param methodName the FieldDeclaration's fragment names
+ * @param typeDecl the TypeDeclaration
+ * @return all references that can potentially get violated if an override happens
+ */
+ def static private referencesThatCanGetViolated(String fragmentName, TypeDeclaration typeDecl) {
+ val List references = newArrayList
+ var TypeDeclaration superclassWithSameField = allTypeDeclarationInWorkSpace.findFirst[it.resolveBinding.qualifiedName == typeDecl.resolveBinding.qualifiedName]
+ var boolean found = false
+ while(superclassWithSameField.hasSuperClass && !found) {
+ superclassWithSameField = superclassWithSameField.superClass
+ found = !isUniqueFieldIn(fragmentName, superclassWithSameField)
+ }
+
+ if (!found) {
+ return references
+ }
+
+ val fieldInSuperClass = superclassWithSameField.bodyDeclarations.findFirst[
+ it instanceof FieldDeclaration && ((it as FieldDeclaration).fragments as List).exists[
+ it.name.identifier == fragmentName
+ ]
+ ] as FieldDeclaration
+
+ val List a = newArrayList
+ a.add(fieldInSuperClass)
+ for (t : allTypeDeclarationInWorkSpace) {
+ val refs = references(a, t)
+ for (r : refs) {
+ val refTypeDecl = Utils.getTypeDeclaration(r)
+ if (refTypeDecl.resolveBinding.isEqualTo(typeDecl.resolveBinding) ||
+ refTypeDecl.resolveBinding.isSubClassOf(typeDecl.resolveBinding) ||
+ (r.parent instanceof QualifiedName && (getTypeOfFieldOrVarDeclOfName(r.parent as QualifiedName, refTypeDecl).resolveBinding.isEqualTo(typeDecl.resolveBinding) ||
+ getTypeOfFieldOrVarDeclOfName(r.parent as QualifiedName, refTypeDecl).resolveBinding.isSubClassOf(typeDecl.resolveBinding))) ) {
+
+ references.add(r)
+ }
+ }
+ }
+ references
+ }
+
+ /**
+ * Gets all references to a MethodDeclaration in one of the given TypeDeclaration's superclass, that can potentially get violated of it gets overridden.
+ * @param methodName the MethodDeclaration's name
+ * @param methodParameters the MethodDeclaration's parameters
+ * @param typeDecl the TypeDeclaration
+ * @return all references that can potentially get violated if an override happens
+ */
+ def private static referencesThatCanGetViolated(String methodName, List methodParameters, TypeDeclaration typeDecl) {
+ val List references = newArrayList
+ var TypeDeclaration superclassWithSameMethod = allTypeDeclarationInWorkSpace.findFirst[it.resolveBinding.qualifiedName == typeDecl.resolveBinding.qualifiedName]
+ var boolean found = false
+ while(superclassWithSameMethod.hasSuperClass && !found) {
+ superclassWithSameMethod = superclassWithSameMethod.superClass
+ found = !isUniqueMethodIn(methodName, methodParameters, superclassWithSameMethod)
+ }
+
+ if (!found) {
+ return references
+ }
+
+ val methodInSuperClass = getMethodFromClass(methodName, methodParameters, superclassWithSameMethod)
+ val List a = newArrayList
+ a.add(methodInSuperClass)
+ for (t : allTypeDeclarationInWorkSpace) {
+ val refs = references(a, t)
+ for (r : refs) {
+ val refTypeDecl = Utils.getTypeDeclaration(r)
+ if (refTypeDecl.resolveBinding.isEqualTo(typeDecl.resolveBinding) ||
+ refTypeDecl.resolveBinding.isSubClassOf(typeDecl.resolveBinding) ||
+ ( (r.parent as MethodInvocation).expression !== null && (getTypeOfFieldOrVarDeclOfName((r.parent as MethodInvocation).expression as Name, refTypeDecl).resolveBinding.isEqualTo(typeDecl.resolveBinding) ||
+ getTypeOfFieldOrVarDeclOfName((r.parent as MethodInvocation).expression as Name, refTypeDecl).resolveBinding.isSubClassOf(typeDecl.resolveBinding))) ) {
+
+ references.add(r)
+ }
+ }
+ }
+ references
+ }
+
+ /**
+ * Gets all the references to a FieldDeclaration, and separates them by their visibility.
+ * @param whichReferences decides if whether the public, or non-public references are returned
+ * @param fragmentNames the FieldDeclaration's fragment names
+ * @param targetTypeDecl the FieldDeclaration's TypeDeclaration
+ * @return if whichReferences equals "public", the references that can get accessed via public interface are returned (list of ASTNodes)
+ * if whichReferences equals "nonPublic", the references the cannot get accessed via public interface are returned (list of ASTNodes)
+ */
+ def private static references(String whichReferences, List fragmentNames, TypeDeclaration targetTypeDecl) {
+ val List publicReferences = newArrayList
+ val List nonPublicReferences = newArrayList
+
+ for(fragmentName : fragmentNames) {
+ val allReferences = referencesThatCanGetViolated(fragmentName, targetTypeDecl)
+ val Queue methodsToCheck = newLinkedList
+
+ for(ref : allReferences) {
+ if(Utils.getMethodDeclaration(ref) !== null && Utils.getMethodDeclaration(ref).visibility == Visibility.PUBLIC) {
+ publicReferences.add(ref)
+ } else if (Utils.getMethodDeclaration(ref) !== null && Utils.getMethodDeclaration(ref).visibility != Visibility.PUBLIC){
+ methodsToCheck.add(Utils.getMethodDeclaration(ref))
+
+ while(!methodsToCheck.empty) {
+ val method = methodsToCheck.remove
+ var List methodRefs = newArrayList
+ for (t : allTypeDeclarationInWorkSpace) {
+ val List tmp = newArrayList
+ tmp.add(method)
+ methodRefs.addAll(references(tmp, t))
+ }
+ if(!methodRefs.empty) {
+ for(methodRef : methodRefs) {
+ if(Utils.getMethodDeclaration(methodRef) !== null && Utils.getMethodDeclaration(methodRef).visibility == Visibility.PUBLIC) {
+ publicReferences.add(ref)
+ } else if (Utils.getMethodDeclaration(methodRef) !== null && Utils.getMethodDeclaration(methodRef).visibility != Visibility.PUBLIC) {
+ methodsToCheck.add(Utils.getMethodDeclaration(methodRef))
+ } else if(Utils.getMethodDeclaration(methodRef) === null) {
+ publicReferences.add(ref)
+ }
+ }
+ } else {
+ if(!nonPublicReferences.exists[it == ref]) {
+ nonPublicReferences.add(ref)
+ }
+ }
+ }
+ } else if(Utils.getMethodDeclaration(ref) === null) {
+ publicReferences.add(ref)
+ }
+ }
+ }
+
+ if(whichReferences == "public") {
+ return publicReferences
+ } else if(whichReferences == "nonPublic") {
+ return nonPublicReferences
+ }
+ }
+
+ /**
+ * Gets all the references to a MethodDeclaration, and separates them by their visibility.
+ * @param whichReferences decides if whether the public, or non-public references are returned
+ * @param methodName the MethodDeclaration's name
+ * @param mathodParameters the MethodDeclaration's parameters
+ * @param targetTypeDecl the MethodDeclaration's TypeDeclaration
+ * @return if whichReferences equals "public", the references that can get accessed via public interface are returned (list of ASTNodes)
+ * if whichReferences equals "nonPublic", the references the cannot get accessed via public interface are returned (list of ASTNodes)
+ */
+ def private static references(String whichReferences, String methodName, List methodParameters,TypeDeclaration targetTypeDecl) {
+ val List publicReferences = newArrayList
+ val List nonPublicReferences = newArrayList
+
+ val allReferences = referencesThatCanGetViolated(methodName, methodParameters, targetTypeDecl)
+ val Queue methodsToCheck = newLinkedList
+
+ for(ref : allReferences) {
+ if(Utils.getMethodDeclaration(ref) !== null && Utils.getMethodDeclaration(ref).visibility == Visibility.PUBLIC) {
+ publicReferences.add(ref)
+ } else if (Utils.getMethodDeclaration(ref) !== null && Utils.getMethodDeclaration(ref).visibility != Visibility.PUBLIC){
+ methodsToCheck.add(Utils.getMethodDeclaration(ref))
+
+ while(!methodsToCheck.empty) {
+ val method = methodsToCheck.remove
+ var List methodRefs = newArrayList
+ for (t : allTypeDeclarationInWorkSpace) {
+ val List tmp = newArrayList
+ tmp.add(method)
+ methodRefs.addAll(references(tmp, t))
+ }
+
+ if(!methodRefs.empty) {
+ for(methodRef : methodRefs) {
+ if(Utils.getMethodDeclaration(methodRef) !== null && Utils.getMethodDeclaration(methodRef).visibility == Visibility.PUBLIC) {
+ publicReferences.add(ref)
+ } else if (Utils.getMethodDeclaration(methodRef) !== null && Utils.getMethodDeclaration(methodRef).visibility != Visibility.PUBLIC) {
+ methodsToCheck.add(Utils.getMethodDeclaration(methodRef))
+ } else if(Utils.getMethodDeclaration(methodRef) === null) {
+ publicReferences.add(ref)
+ }
+ }
+ } else {
+ if(!nonPublicReferences.exists[it == ref]) {
+ nonPublicReferences.add(ref)
+ }
+ }
+ }
+ } else if(Utils.getMethodDeclaration(ref) === null) {
+ publicReferences.add(ref)
+ }
+ }
+
+ if(whichReferences == "public") {
+ return publicReferences
+ } else if(whichReferences == "nonPublic") {
+ return nonPublicReferences
+ }
+ }
+
+ /**
+ * Gets all references to a FieldDeclaration that cannot get accessed via public interface.
+ * @param fragmentNames the FieldDeclaration's fragment names
+ * @param targetTypeDeclaration the FieldDeclaration's TypeDeclaration
+ * @return list of ASTNodes
+ */
+ def protected static nonPublicReferences(List fragmentNames, TypeDeclaration targetTypeDecl) {
+ references("nonPublic", fragmentNames, targetTypeDecl)
+ }
+
+ /**
+ * Gets all subclasses of a TypeDeclaration.
+ * @param typeDecl the TypeDeclaration
+ * @return all subclasses of typeDecl (list of org.eclipse.jdt.core.dom.TypeDeclaration)
+ */
+ def protected static getAllSubClasses(TypeDeclaration typeDecl) {
+ val binding = typeDecl.resolveBinding
+ val List subClasses = newArrayList
+
+ allTypeDeclarationInWorkSpace.forEach[
+ if(it.resolveBinding.isSubClassOf(binding) && typeDecl != it) {
+ subClasses.add(it)
+ }
+ ]
+ subClasses
+ }
+
+ /**
+ * Gets all MethodDeclaration with the same name and parameter types as the given name and parameter types from the given TypeDeclaration's subclasses.
+ * @param methodName the identifier of the method
+ * @param methodParameters the list of parameters of the method
+ * @param targetTypeDeclaration the TypeDeclaration
+ * @return list of MethodDeclarations
+ */
+ def protected static overridesOf(String methodName, List methodParameters, TypeDeclaration targetTypeDeclaration) {
+ val subClasses = targetTypeDeclaration.allSubClasses
+ val List overriddenMethods = newArrayList
+ subClasses.forEach[
+ if(!isUniqueMethodIn(methodName, methodParameters, it)) {
+ overriddenMethods.add(getMethodFromClass(methodName, methodParameters, it))
+ }
+ ]
+ overriddenMethods
+ }
}
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/api/ClassRefactoring.xtend b/hu.elte.refjava.lang/src/hu/elte/refjava/api/ClassRefactoring.xtend
new file mode 100644
index 0000000..36eb60a
--- /dev/null
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/api/ClassRefactoring.xtend
@@ -0,0 +1,281 @@
+package hu.elte.refjava.api
+
+import hu.elte.refjava.api.patterns.ASTBuilder
+import hu.elte.refjava.api.patterns.PatternMatcher
+import hu.elte.refjava.api.patterns.PatternParser
+import hu.elte.refjava.api.patterns.Utils
+import hu.elte.refjava.lang.refJava.PMethodDeclaration
+import java.util.List
+import org.eclipse.jdt.core.dom.ASTNode
+import org.eclipse.jdt.core.dom.FieldDeclaration
+import org.eclipse.jdt.core.dom.MethodDeclaration
+import org.eclipse.jdt.core.dom.TypeDeclaration
+import org.eclipse.jdt.core.dom.VariableDeclarationFragment
+import org.eclipse.jface.text.Document
+import org.eclipse.jface.text.IDocument
+
+import static hu.elte.refjava.api.Check.*
+import hu.elte.refjava.lang.refJava.Visibility
+
+class ClassRefactoring implements Refactoring {
+
+ List extends ASTNode> target
+ IDocument document
+
+ val PatternMatcher matcher
+ val ASTBuilder builder
+ val String matchingString
+ val String replacementString
+ val RefactoringType refactoringType
+ protected String targetString
+ protected String definitionString
+ protected String matchingTypeReferenceString
+ protected String replacementTypeReferenceString
+ protected String targetTypeReferenceString
+ protected String definitionTypeReferenceString
+ List replacement
+
+ enum RefactoringType {
+ NEW_METHOD,
+ METHOD_LIFT,
+ FIELD_LIFT
+ }
+
+ protected new(String matchingPatternString, String replacementPatternString) {
+ nameBindings.clear
+ typeBindings.clear
+ parameterBindings.clear
+ visibilityBindings.clear
+ argumentBindings.clear
+ setMetaVariables
+ this.matcher = new PatternMatcher(PatternParser.parse(matchingPatternString))
+ this.builder = new ASTBuilder(PatternParser.parse(replacementPatternString))
+ this.matchingString = matchingPatternString
+ this.replacementString = replacementPatternString
+ this.refactoringType = if(replacementPatternString != "nothing") {
+ RefactoringType.NEW_METHOD
+ } else {
+ if(PatternParser.parse(matchingPatternString).patterns.head instanceof PMethodDeclaration) {
+ RefactoringType.METHOD_LIFT
+ } else {
+ RefactoringType.FIELD_LIFT
+ }
+ }
+
+ if (replacementString == "nothing" && definitionString == "target") {
+ this.definitionString = matchingString
+ this.definitionTypeReferenceString = matchingTypeReferenceString
+ }
+ }
+
+ override init(List extends ASTNode> target, IDocument document, List allTypeDeclInWorkspace) {
+ this.target = target
+ this.document = document
+ Check.allTypeDeclarationInWorkSpace = allTypeDeclInWorkspace
+ }
+
+ override apply() {
+ return if(!safeTargetCheck) {
+ Status.TARGET_MATCH_FAILED
+ } else if (!safeMatch) {
+ Status.MATCH_FAILED
+ } else if (!safeCheck) {
+ Status.CHECK_FAILED
+ } else if (!safeBuild) {
+ Status.BUILD_FAILED
+ } else if (!safeReplace) {
+ Status.REPLACEMENT_FAILED
+ } else {
+ Status.SUCCESS
+ }
+ }
+
+ def private safeMatch() {
+ try {
+ if (!matcher.match(target, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, matchingTypeReferenceString)) {
+ return false
+ }
+ target = matcher.modifiedTarget.toList
+ bindings.putAll(matcher.bindings)
+ true
+ } catch (Exception e) {
+ println(e)
+ false
+ }
+ }
+
+ def protected void setMetaVariables() {
+ //empty
+ }
+
+ def protected safeTargetCheck() {
+ true
+ }
+
+ def protected targetCheck(String targetPatternString) {
+ try {
+ this.targetString = targetPatternString
+ if(!matcher.match(PatternParser.parse(targetPatternString), target, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, targetTypeReferenceString)) {
+ return false
+ }
+ bindings.putAll(matcher.bindings)
+ true
+ } catch (Exception e) {
+ println(e)
+ false
+ }
+ }
+
+ def private safeCheck() {
+ try {
+ check()
+ } catch (Exception e) {
+ println(e)
+ false
+ }
+ }
+
+ def protected check() {
+
+ if(refactoringType == RefactoringType.NEW_METHOD) {
+
+ val iCompUnit = Utils.getICompilationUnit(target.head)
+ val compUnit = Utils.parseSourceCode(iCompUnit)
+ compUnit.recordModifications
+
+ val definitionPattern = PatternParser.parse(definitionString)
+ val newMethod = builder.build(definitionPattern, compUnit.AST, bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, definitionTypeReferenceString).head as MethodDeclaration
+ val targetClass = compUnit.types.findFirst[(it as TypeDeclaration).resolveBinding.qualifiedName == Utils.getTypeDeclaration(target.head).resolveBinding.qualifiedName ] as TypeDeclaration
+ targetClass.bodyDeclarations.add(newMethod)
+ Utils.applyChanges(compUnit, document)
+
+ val compUnit2 = Utils.parseSourceCode(iCompUnit)
+ val targetClass2 = compUnit2.types.findFirst[(it as TypeDeclaration).resolveBinding.qualifiedName == Utils.getTypeDeclaration(target.head).resolveBinding.qualifiedName] as TypeDeclaration
+ val newMethodInClass = targetClass2.bodyDeclarations.last
+ val List definition = newArrayList
+ definition.add(newMethodInClass)
+
+ val overrideCheck = if(isOverrideIn(getMethodName(definition), parameters(definition), enclosingClass(target))) {
+ !isLessVisible(visibility(definition), visibility(overridenMethodFrom(getMethodName(definition), parameters(definition), enclosingClass(target))))
+ && isSubTypeOf(type(definition), type(overridenMethodFrom(getMethodName(definition), parameters(definition), enclosingClass(target))))
+ && visibility(overridenMethodFrom(getMethodName(definition), parameters(definition), enclosingClass(target))) != Visibility.PUBLIC
+ && publicReferences(getMethodName(definition), parameters(definition), enclosingClass(target)).empty } else { true }
+
+ val safeCheck = isUniqueMethodIn(getMethodName(definition), parameters(definition), enclosingClass(target))
+ && overrideCheck
+ && overridesOf(getMethodName(definition), parameters(definition), enclosingClass(target)).forall[
+ !isLessVisible(visibility(it), visibility(definition)) &&
+ isSubTypeOf(type(it), type(definition))]
+
+ compUnit2.recordModifications
+ targetClass2.bodyDeclarations.remove(newMethodInClass)
+ Utils.applyChanges(compUnit2, document)
+ safeCheck
+
+ } else {
+ if(refactoringType == RefactoringType.METHOD_LIFT) {
+
+ val privateCheck = if (isPrivate(target)) { references(target, enclosingClass(target)).empty } else { true }
+ val overrideCheck = if(isOverrideIn(getMethodName(target), parameters(target), superClass(enclosingClass(target)))) {
+ !isLessVisible(visibility(target), visibility(overridenMethodFrom(getMethodName(target), parameters(target), superClass(enclosingClass(target)))))
+ && isSubTypeOf(type(target), type(overridenMethodFrom(getMethodName(target), parameters(target), superClass(enclosingClass(target)))))
+ && visibility(overridenMethodFrom(getMethodName(target), parameters(target), superClass(enclosingClass(target)))) != Visibility.PUBLIC
+ && publicReferences(getMethodName(target), parameters(target), superClass(enclosingClass(target))).empty } else { true }
+
+ return hasSuperClass(enclosingClass(target))
+ && privateCheck
+ && accessedFieldsOfEnclosingClass(target, enclosingClass(target)).empty
+ && accessedMethodsOfEnclosingClass(target, enclosingClass(target)).empty
+ && isUniqueMethodIn(getMethodName(target), parameters(target), superClass(enclosingClass(target)))
+ && overrideCheck
+ && overridesOf(getMethodName(target), parameters(target), superClass(enclosingClass(target))).forall[
+ !isLessVisible(visibility(it), visibility(target)) &&
+ isSubTypeOf(type(it), type(target))]
+
+ } else if (refactoringType == RefactoringType.FIELD_LIFT) {
+
+ val privateCheck = if (isPrivate(target)) { references(target, enclosingClass(target)).empty } else { true }
+ return hasSuperClass(enclosingClass(target))
+ && privateCheck
+ && isUniqueFieldIn(getFragmentNames(target), superClass(enclosingClass(target)))
+ && publicReferences(getFragmentNames(target), superClass(enclosingClass(target))).empty
+ && nonPublicReferences(getFragmentNames(target), superClass(enclosingClass(target))).forall [
+ isSubTypeOf(Check.type(target), type(referredField(it))) ]
+ }
+ false
+ }
+ }
+
+ def private safeBuild() {
+ try {
+ if(refactoringType == RefactoringType.NEW_METHOD) {
+ val replacementPattern = PatternParser.parse(replacementString)
+ replacement = builder.build(replacementPattern, target.head.AST, bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, definitionTypeReferenceString)
+ }
+ true
+ } catch (Exception e) {
+ println(e)
+ false
+ }
+ }
+
+ def private safeReplace() {
+ try {
+ //we only need to replace if we creating a new method
+ if (refactoringType == RefactoringType.NEW_METHOD) {
+ val rewrite = builder.rewrite
+ target.tail.forEach[rewrite.remove(it, null)]
+
+ val group = rewrite.createGroupNode(replacement)
+ rewrite.replace( target.head, group, null)
+ var edits = rewrite.rewriteAST(document, null)
+ edits.apply(document)
+ }
+
+ val targetTypeDeclaration = Utils.getTypeDeclaration(target.head)
+ var superClass = superClass(targetTypeDeclaration)
+ val superCompUnit = Utils.getCompilationUnit(superClass)
+ val superICompUnit = Utils.getICompilationUnit(superCompUnit)
+
+ val targetICompUnit = Utils.getICompilationUnit(target.head)
+ val targetCompUnit = Utils.parseSourceCode(targetICompUnit)
+ targetCompUnit.recordModifications
+
+ val definitionPattern = PatternParser.parse(definitionString)
+ var objectToInsertOrMove = builder.build(definitionPattern, targetCompUnit.AST, bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, definitionTypeReferenceString).head
+ val targetClass = targetCompUnit.types.findFirst[(it as TypeDeclaration).name.identifier == targetTypeDeclaration.name.identifier] as TypeDeclaration
+
+ if(refactoringType == RefactoringType.NEW_METHOD) {
+ targetClass.bodyDeclarations.add(objectToInsertOrMove)
+ } else {
+ if(superICompUnit != targetICompUnit) {
+ superCompUnit.recordModifications
+ objectToInsertOrMove = builder.build(definitionPattern, superCompUnit.AST , bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, definitionTypeReferenceString).head
+ } else {
+ superClass = targetCompUnit.types.findFirst[(it as TypeDeclaration).resolveBinding.isEqualTo(targetClass.superclassType.resolveBinding)]
+ }
+
+ val methodOrFieldToDelete = if(refactoringType == RefactoringType.METHOD_LIFT){
+ getMethodFromClass(getMethodName(target), parameters(target), targetClass)
+ } else if (refactoringType == RefactoringType.FIELD_LIFT) {
+ targetClass.bodyDeclarations.findFirst[it instanceof FieldDeclaration &&
+ ((it as FieldDeclaration).fragments.head as VariableDeclarationFragment).name.identifier == ((target.head as FieldDeclaration).fragments.head as VariableDeclarationFragment).name.identifier]
+ }
+
+ superClass.bodyDeclarations.add(objectToInsertOrMove)
+ targetClass.bodyDeclarations.remove(methodOrFieldToDelete)
+
+ if(superICompUnit != targetICompUnit) {
+ val superDocument = new Document(superICompUnit.source)
+ Utils.applyChanges(superCompUnit, superDocument)
+ superICompUnit.getBuffer.setContents(superDocument.get)
+ }
+ }
+ Utils.applyChanges(targetCompUnit, document)
+ true
+ } catch (Exception e) {
+ println(e)
+ return false
+ }
+ }
+}
\ No newline at end of file
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/api/LambdaRefactoring.xtend b/hu.elte.refjava.lang/src/hu/elte/refjava/api/LambdaRefactoring.xtend
new file mode 100644
index 0000000..cb4f5ca
--- /dev/null
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/api/LambdaRefactoring.xtend
@@ -0,0 +1,221 @@
+package hu.elte.refjava.api
+
+import hu.elte.refjava.api.patterns.ASTBuilder
+import hu.elte.refjava.api.patterns.PatternMatcher
+import hu.elte.refjava.api.patterns.PatternParser
+import hu.elte.refjava.api.patterns.Utils
+import hu.elte.refjava.lang.refJava.PConstructorCall
+import hu.elte.refjava.lang.refJava.PMemberFeatureCall
+import hu.elte.refjava.lang.refJava.PMetaVariable
+import java.util.List
+import org.eclipse.jdt.core.dom.ASTNode
+import org.eclipse.jdt.core.dom.ExpressionStatement
+import org.eclipse.jdt.core.dom.TypeDeclaration
+import org.eclipse.jface.text.Document
+import org.eclipse.jface.text.IDocument
+
+import static hu.elte.refjava.api.Check.*
+
+class LambdaRefactoring implements Refactoring {
+
+ List extends ASTNode> target
+ List allTypeDecl
+ IDocument document
+
+ val PatternMatcher matcher
+ val ASTBuilder builder
+ val String matchingString
+ val String replacementString
+ val RefactoringType refactoringType
+ protected TypeDeclaration interfaceToModify
+ protected String definitionString
+ protected String matchingTypeReferenceString
+ protected String replacementTypeReferenceString
+ protected String targetTypeReferenceString
+ protected String definitionTypeReferenceString
+ List replacement
+
+ enum RefactoringType {
+ MODIFICATION,
+ NEW
+ }
+
+ protected new(String matchingPatternString, String replacementPatternString) {
+ nameBindings.clear
+ typeBindings.clear
+ parameterBindings.clear
+ visibilityBindings.clear
+ argumentBindings.clear
+ setMetaVariables
+ this.matcher = new PatternMatcher(PatternParser.parse(matchingPatternString))
+ this.builder = new ASTBuilder(PatternParser.parse(replacementPatternString))
+ this.matchingString = matchingPatternString
+ this.replacementString = replacementPatternString
+
+ val matchingPatterns = PatternParser.parse(matchingPatternString).patterns
+ if (matchingPatterns.exists[Utils.isValidLambdaExpression(it)]) {
+ this.refactoringType = RefactoringType.MODIFICATION
+ } else {
+ this.interfaceToModify = null
+ this.refactoringType = RefactoringType.NEW
+ }
+ }
+
+ override init(List extends ASTNode> target, IDocument document, List allTypeDeclInWorkspace) {
+ this.target = target
+ this.document = document
+ this.allTypeDecl = allTypeDeclInWorkspace
+ Check.allTypeDeclarationInWorkSpace = allTypeDeclInWorkspace
+
+ }
+
+ override apply() {
+ return if(!safeTargetCheck) {
+ Status.TARGET_MATCH_FAILED
+ } else if (!safeMatch) {
+ Status.MATCH_FAILED
+ } else if (!safeCheck) {
+ Status.CHECK_FAILED
+ } else if (!safeBuild) {
+ Status.BUILD_FAILED
+ } else if (!safeReplace) {
+ Status.REPLACEMENT_FAILED
+ } else {
+ Status.SUCCESS
+ }
+ }
+
+ def private safeMatch() {
+ try {
+ if (!matcher.match(target, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, matchingTypeReferenceString)) {
+ return false
+ }
+ target = matcher.modifiedTarget.toList
+ bindings.putAll(matcher.bindings)
+ true
+ } catch (Exception e) {
+ println(e)
+ false
+ }
+ }
+
+ def protected void setMetaVariables() {
+ //empty
+ }
+
+ def protected safeTargetCheck() {
+ true
+ }
+
+ def protected targetCheck(String targetPatternString) {
+ try {
+ if(!matcher.match(PatternParser.parse(targetPatternString), target, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, targetTypeReferenceString)) {
+ return false
+ }
+ bindings.putAll(matcher.bindings)
+ true
+ } catch (Exception e) {
+ println(e)
+ false
+ }
+ }
+
+ def private safeCheck() {
+ try {
+ check()
+ } catch (Exception e) {
+ println(e)
+ false
+ }
+ }
+
+ def protected check() {
+
+ if(refactoringType == RefactoringType.NEW) {
+ val iCompUnit = Utils.getICompilationUnit(target.head)
+ val compUnit = Utils.parseSourceCode(iCompUnit)
+
+ val replacementPattern = PatternParser.parse(replacementString)
+ val replacementLambdaExpression = replacementPattern.patterns.head
+ if (((replacementLambdaExpression as PMemberFeatureCall).memberCallTarget as PConstructorCall).metaName !== null) {
+ val metaVarName = (((replacementLambdaExpression as PMemberFeatureCall).memberCallTarget as PConstructorCall).metaName as PMetaVariable).name
+ nameBindings.put(metaVarName, generateNewName)
+ }
+
+ val newLambdaExpression = builder.build(replacementPattern, compUnit.AST, bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, replacementTypeReferenceString).head as ExpressionStatement
+ return isFresh(getLambdaName(newLambdaExpression))
+ && (lambdaVariableAssignments(getLambdaBody(newLambdaExpression)).forall[isDeclaredIn(it, getLambdaBody(newLambdaExpression))])
+
+ } else {
+
+ val matchingLambdaExpression = PatternParser.parse(matchingString).patterns.get(0) as PMemberFeatureCall
+ val interfaceName = if((matchingLambdaExpression.memberCallTarget as PConstructorCall).metaName !== null) {
+ nameBindings.get(((matchingLambdaExpression.memberCallTarget as PConstructorCall).metaName as PMetaVariable).name)
+ } else {
+ (matchingLambdaExpression.memberCallTarget as PConstructorCall).name
+ }
+ this.interfaceToModify = allTypeDecl.findFirst[it.name.identifier == interfaceName]
+
+ return references(interfaceToModify).size == 1 &&
+ contains(references(interfaceToModify), target)
+ }
+ }
+
+ def private safeBuild() {
+ try {
+ replacement = builder.build(target.head.AST, bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, replacementTypeReferenceString)
+ true
+ } catch (Exception e) {
+ println(e)
+ false
+ }
+ }
+
+ def private safeReplace() {
+ try {
+ val rewrite = builder.rewrite
+ target.tail.forEach[rewrite.remove(it, null)]
+ val group = rewrite.createGroupNode(replacement)
+ rewrite.replace(target.head, group, null)
+ var edits = rewrite.rewriteAST(document, null)
+ edits.apply(document)
+
+ val iCompUnit= Utils.getICompilationUnit(target.head)
+ val compUnit = Utils.parseSourceCode(iCompUnit)
+ compUnit.recordModifications
+
+ val replacementLambdaExpression = PatternParser.parse(replacementString).patterns.get(0) as PMemberFeatureCall
+ if(refactoringType == RefactoringType.NEW) {
+ //if we are defining a new lambda expression, we just simply add a new interface to the target document
+ val newInterface = builder.buildNewInterface(replacementLambdaExpression, compUnit.AST, bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, replacementTypeReferenceString)
+ compUnit.types.add(newInterface)
+ } else {
+ //if we modifying an existing lambda expression, we have to find out where is the existing interface declaration on the workspace
+ val interfaceCompUnit = Utils.getCompilationUnit(interfaceToModify)
+ val interfaceICompUnit = Utils.getICompilationUnit(interfaceCompUnit)
+ if(interfaceICompUnit != iCompUnit) {
+ //if the interface's document isn't the same as the target document, we are going to remove that interface from that document and then add the new
+ interfaceCompUnit.recordModifications
+ val newInterface = builder.buildNewInterface(replacementLambdaExpression, interfaceCompUnit.AST, bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, replacementTypeReferenceString)
+ interfaceCompUnit.types.remove(interfaceToModify)
+ interfaceCompUnit.types.add(newInterface)
+
+ val interfaceDocument = new Document(interfaceICompUnit.source)
+ Utils.applyChanges(interfaceCompUnit, interfaceDocument)
+ interfaceICompUnit.getBuffer.setContents(interfaceDocument.get)
+ } else {
+ //if the interface's document is the same as the target document, we just simply remove the interface from the target document and then add the new
+ val newInterface = builder.buildNewInterface(replacementLambdaExpression, compUnit.AST, bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, replacementTypeReferenceString)
+ val interfaceToRemove = compUnit.types.findFirst[(it as TypeDeclaration).resolveBinding.qualifiedName == interfaceToModify.resolveBinding.qualifiedName] as TypeDeclaration
+ compUnit.types.remove(interfaceToRemove)
+ compUnit.types.add(newInterface)
+ }
+ }
+ Utils.applyChanges(compUnit, document)
+ true
+ } catch (Exception e) {
+ println(e)
+ return false
+ }
+ }
+}
\ No newline at end of file
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/api/LocalRefactoring.xtend b/hu.elte.refjava.lang/src/hu/elte/refjava/api/LocalRefactoring.xtend
index cb53f41..4209c6e 100644
--- a/hu.elte.refjava.lang/src/hu/elte/refjava/api/LocalRefactoring.xtend
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/api/LocalRefactoring.xtend
@@ -4,10 +4,12 @@ import hu.elte.refjava.api.patterns.ASTBuilder
import hu.elte.refjava.api.patterns.PatternMatcher
import hu.elte.refjava.api.patterns.PatternParser
import java.util.List
-import java.util.Map
import org.eclipse.jdt.core.dom.ASTNode
+import org.eclipse.jdt.core.dom.TypeDeclaration
import org.eclipse.jface.text.IDocument
+import static hu.elte.refjava.api.Check.*
+
class LocalRefactoring implements Refactoring {
List extends ASTNode> target
@@ -15,15 +17,24 @@ class LocalRefactoring implements Refactoring {
val PatternMatcher matcher
val ASTBuilder builder
- protected val Map> bindings = newHashMap
+ protected String matchingTypeReferenceString
+ protected String replacementTypeReferenceString
+ protected String targetTypeReferenceString
+ protected String definitionTypeReferenceString
List replacement
- protected new(String matchingPatternString, String replacementPatternString) {
- matcher = new PatternMatcher(PatternParser.parse(matchingPatternString))
- builder = new ASTBuilder(PatternParser.parse(replacementPatternString))
+ new(String matchingPatternString, String replacementPatternString) {
+ nameBindings.clear
+ typeBindings.clear
+ parameterBindings.clear
+ visibilityBindings.clear
+ argumentBindings.clear
+ setMetaVariables
+ this.matcher = new PatternMatcher(PatternParser.parse(matchingPatternString))
+ this.builder = new ASTBuilder(PatternParser.parse(replacementPatternString))
}
- override init(List extends ASTNode> target, IDocument document) {
+ override init(List extends ASTNode> target, IDocument document, List allTypeDeclInWorkspace) {
this.target = target
this.document = document
}
@@ -43,51 +54,58 @@ class LocalRefactoring implements Refactoring {
}
def private safeMatch() {
- if (!matcher.match(target)) {
+ if (!matcher.match(target, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, matchingTypeReferenceString)) {
return false
}
-
bindings.putAll(matcher.bindings)
- return true
+ true
}
def private safeCheck() {
try {
check()
} catch (Exception e) {
+ println(e)
false
}
}
+
+ def protected void setMetaVariables() {
+ //empty
+ }
def protected check() {
- Check.isInsideBlock(target)
+ isInsideBlock(target)
}
def private safeBuild() {
try {
- replacement = builder.build(target.head.AST, bindings)
+ replacement = builder.build(target.head.AST, bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, replacementTypeReferenceString)
+ true
} catch (Exception e) {
- return false
+ println(e)
+ false
}
-
- return true
}
def private safeReplace() {
try {
val rewrite = builder.rewrite
target.tail.forEach[rewrite.remove(it, null)]
-
- val group = rewrite.createGroupNode(replacement)
+
+ val group = if (replacement.size == 0) {
+ null
+ } else {
+ rewrite.createGroupNode(replacement)
+ }
+
rewrite.replace(target.head, group, null)
-
val edits = rewrite.rewriteAST(document, null)
edits.apply(document)
+ true
} catch (Exception e) {
- return false
+ println(e)
+ false
}
-
- return true
}
-
}
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/api/Refactoring.xtend b/hu.elte.refjava.lang/src/hu/elte/refjava/api/Refactoring.xtend
index d5d6230..04c4428 100644
--- a/hu.elte.refjava.lang/src/hu/elte/refjava/api/Refactoring.xtend
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/api/Refactoring.xtend
@@ -1,21 +1,36 @@
package hu.elte.refjava.api
+import hu.elte.refjava.lang.refJava.Visibility
import java.util.List
+import java.util.Map
import org.eclipse.jdt.core.dom.ASTNode
+import org.eclipse.jdt.core.dom.Expression
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration
+import org.eclipse.jdt.core.dom.Type
+import org.eclipse.jdt.core.dom.TypeDeclaration
import org.eclipse.jface.text.IDocument
interface Refactoring {
-
+
+ val Map> bindings = newHashMap
+ val Map nameBindings = newHashMap
+ val Map typeBindings = newHashMap
+ val Map> parameterBindings = newHashMap
+ val Map visibilityBindings = newHashMap
+ val Map> argumentBindings = newHashMap
+
+
enum Status {
SUCCESS,
MATCH_FAILED,
CHECK_FAILED,
BUILD_FAILED,
- REPLACEMENT_FAILED
+ REPLACEMENT_FAILED,
+ TARGET_MATCH_FAILED
}
-
- def void init(List extends ASTNode> target, IDocument document) {}
+
+ def void init(List extends ASTNode> target, IDocument document, List allTypeDeclInWorkspace)
def Status apply()
-}
+}
\ No newline at end of file
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/api/patterns/ASTBuilder.xtend b/hu.elte.refjava.lang/src/hu/elte/refjava/api/patterns/ASTBuilder.xtend
index d321ee7..9670170 100644
--- a/hu.elte.refjava.lang/src/hu/elte/refjava/api/patterns/ASTBuilder.xtend
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/api/patterns/ASTBuilder.xtend
@@ -1,23 +1,45 @@
package hu.elte.refjava.api.patterns
+import hu.elte.refjava.api.Check
import hu.elte.refjava.lang.refJava.PBlockExpression
+import hu.elte.refjava.lang.refJava.PConstructorCall
import hu.elte.refjava.lang.refJava.PExpression
+import hu.elte.refjava.lang.refJava.PFeatureCall
+import hu.elte.refjava.lang.refJava.PMemberFeatureCall
import hu.elte.refjava.lang.refJava.PMetaVariable
+import hu.elte.refjava.lang.refJava.PMethodDeclaration
+import hu.elte.refjava.lang.refJava.PNothingExpression
+import hu.elte.refjava.lang.refJava.PTargetExpression
+import hu.elte.refjava.lang.refJava.PVariableDeclaration
import hu.elte.refjava.lang.refJava.Pattern
+import hu.elte.refjava.lang.refJava.Visibility
import java.util.List
import java.util.Map
+import java.util.Queue
import org.eclipse.jdt.core.dom.AST
import org.eclipse.jdt.core.dom.ASTNode
+import org.eclipse.jdt.core.dom.Block
+import org.eclipse.jdt.core.dom.Expression
+import org.eclipse.jdt.core.dom.MethodDeclaration
+import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration
+import org.eclipse.jdt.core.dom.Type
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite
+import hu.elte.refjava.lang.refJava.PReturnExpression
class ASTBuilder {
- val Pattern pattern
-
+ Pattern pattern
AST ast
ASTRewrite rewrite
Map> bindings
-
+ Map nameBindings
+ Map typeBindings
+ Map> parameterBindings
+ Map visibilityBindings
+ Map> argumentBindings
+ Queue typeReferenceQueue
+
new(Pattern pattern) {
this.pattern = pattern
}
@@ -25,15 +47,81 @@ class ASTBuilder {
def getRewrite() {
rewrite
}
-
- def build(AST ast, Map> bindings) {
+
+ def build(Pattern pattern, AST ast, Map> bindings, Map nameBindings, Map typeBindings, Map> parameterBindings, Map visibilityBindings, Map> argumentBindings, String typeRefString) {
+ this.pattern = pattern
+ build(ast, bindings, nameBindings, typeBindings, parameterBindings, visibilityBindings, argumentBindings, typeRefString)
+ }
+
+ def build(AST ast, Map> bindings, Map nameBindings, Map typeBindings, Map> parameterBindings, Map visibilityBindings, Map> argumentBindings, String typeRefString) {
this.ast = ast
this.rewrite = ASTRewrite.create(ast)
this.bindings = bindings
-
- return pattern.patterns.doBuildPatterns
+ this.nameBindings = nameBindings
+ this.typeBindings = typeBindings
+ this.parameterBindings = parameterBindings
+ this.visibilityBindings = visibilityBindings
+ this.argumentBindings = argumentBindings
+
+ if(typeRefString !== null) {
+ val tmp = typeRefString.split("\\|")
+ this.typeReferenceQueue = newLinkedList
+ this.typeReferenceQueue.addAll(tmp)
+ }
+
+ if(pattern.patterns.head instanceof PNothingExpression) {
+ val List emptyList = newArrayList
+ emptyList
+ } else {
+ pattern.patterns.doBuildPatterns
+ }
}
-
+
+ def buildNewInterface(PMemberFeatureCall lambdaExpr, AST ast, Map> bindings, Map nameBindings, Map typeBindings, Map> parameterBindings, Map visibilityBindings, Map> argumentBindings, String typeRefString){
+ this.ast = ast
+ this.bindings = bindings
+ this.nameBindings = nameBindings
+ this.typeBindings = typeBindings
+ this.parameterBindings = parameterBindings
+ this.visibilityBindings = visibilityBindings
+ this.argumentBindings = argumentBindings
+
+ val newInterface = ast.newTypeDeclaration
+ newInterface.interface = true
+
+ if((lambdaExpr.memberCallTarget as PConstructorCall).metaName !== null) {
+ val name = ((lambdaExpr.memberCallTarget as PConstructorCall).metaName as PMetaVariable).name
+ if (nameBindings.get(name) === null) {
+ newInterface.name.identifier = Check.generateNewName()
+ } else {
+ newInterface.name.identifier = nameBindings.get(name)
+ }
+ } else {
+ newInterface.name.identifier = (lambdaExpr.memberCallTarget as PConstructorCall).name
+ }
+
+ if(typeRefString !== null) {
+ val tmp = typeRefString.split("\\|")
+ this.typeReferenceQueue = newLinkedList
+ this.typeReferenceQueue.addAll(tmp)
+ }
+
+ val lambdaExpressionBody = (lambdaExpr.memberCallTarget as PConstructorCall).elements
+ val newInterfaceBodyDeclarations = lambdaExpressionBody.doBuildPatterns
+
+ newInterfaceBodyDeclarations.forEach[
+ if(it instanceof MethodDeclaration) {
+ it.body = null
+ }
+ ]
+
+ newInterface.bodyDeclarations.addAll(newInterfaceBodyDeclarations.filter[it instanceof MethodDeclaration])
+ newInterface
+ }
+
+ ///////////////////////
+ // doBuild overloads //
+ ///////////////////////
def private dispatch doBuild(PMetaVariable metaVar) {
val binding = bindings.get(metaVar.name)
if (!binding.empty) {
@@ -41,18 +129,259 @@ class ASTBuilder {
rewrite.createGroupNode(copies)
}
}
-
- def private dispatch ASTNode doBuild(PBlockExpression blockPattern) {
+
+ def private dispatch doBuild(PTargetExpression targetExpr) {
+ val binding = bindings.get("target")
+ if (!binding.empty) {
+ val copies = binding.map[ASTNode.copySubtree(ast, it)]
+ rewrite.createGroupNode(copies)
+ }
+ }
+
+ //constructor call builder
+ def private dispatch doBuild(PConstructorCall constCall) {
+ val class = ast.newClassInstanceCreation
+
+ //adding constructor call name
+ if (constCall.metaName !== null) {
+ val name = (constCall.metaName as PMetaVariable).name
+ class.type = ast.newSimpleType(ast.newName(nameBindings.get(name) ) )
+ } else {
+ class.type = ast.newSimpleType(ast.newName(constCall.name) )
+ }
+
+ //adding constructor call anonymous class declaration (body)
+ if(constCall.anonInstance) {
+ val anonClass = ast.newAnonymousClassDeclaration
+ val buildDeclarations = constCall.elements.doBuildPatterns
+ anonClass.bodyDeclarations.addAll(buildDeclarations)
+ class.anonymousClassDeclaration = anonClass
+ }
+
+ class
+ }
+
+ //method declaration builder
+ def private dispatch ASTNode doBuild(PMethodDeclaration methodDecl) {
+ val method = ast.newMethodDeclaration
+
+ //adding method name
+ if (methodDecl.prefix.metaName !== null) {
+ val name = (methodDecl.prefix.metaName as PMetaVariable).name
+ method.name.identifier = nameBindings.get(name)
+ } else {
+ method.name.identifier = methodDecl.prefix.name
+ }
+
+ //adding method visibility
+ if (methodDecl.prefix.metaVisibility !== null) {
+ val metaVarName = (methodDecl.prefix.metaVisibility as PMetaVariable).name
+ switch visibilityBindings.get(metaVarName) {
+ case PUBLIC: method.modifiers().add(ast.newModifier(ModifierKeyword.PUBLIC_KEYWORD))
+ case PRIVATE: method.modifiers().add(ast.newModifier(ModifierKeyword.PRIVATE_KEYWORD))
+ case PROTECTED: method.modifiers().add(ast.newModifier(ModifierKeyword.PROTECTED_KEYWORD))
+ default: {}
+ }
+ } else {
+ switch methodDecl.prefix.visibility {
+ case PUBLIC: method.modifiers().add(ast.newModifier(ModifierKeyword.PUBLIC_KEYWORD))
+ case PRIVATE: method.modifiers().add(ast.newModifier(ModifierKeyword.PRIVATE_KEYWORD))
+ case PROTECTED: method.modifiers().add(ast.newModifier(ModifierKeyword.PROTECTED_KEYWORD))
+ default: {}
+ }
+ }
+
+ //adding method return type
+ if(methodDecl.prefix.type !== null) {
+ method.returnType2 = Utils.getTypeFromId(typeReferenceQueue.remove, ast)
+ } else {
+ val name = (methodDecl.prefix.metaType as PMetaVariable).name
+ method.returnType2 = ASTNode.copySubtree(ast, typeBindings.get(name)) as Type
+ }
+
+ //adding method parameters
+ if (methodDecl.parameters.size > 0) {
+ for(argument : methodDecl.parameters) {
+ val typeName = typeReferenceQueue.remove
+ val methodParameterDeclaration = ast.newSingleVariableDeclaration
+ methodParameterDeclaration.type = Utils.getTypeFromId(typeName, ast)
+ methodParameterDeclaration.name.identifier = argument.name
+ method.parameters.add(methodParameterDeclaration)
+ }
+ } else if (methodDecl.metaParameters !== null) {
+ val parameterList = parameterBindings.get((methodDecl.metaParameters as PMetaVariable).name)
+ method.parameters.addAll(ASTNode.copySubtrees(ast, parameterList))
+ }
+
+ //adding method body
+ val block = ast.newBlock
+ val methodBody = (methodDecl.body as PBlockExpression).expressions
+ var List methodBodyList = newArrayList
+ for(element : methodBody) {
+ if(element instanceof PMetaVariable) {
+ val binding = bindings.get((element as PMetaVariable).name)
+ val copies = binding.map[ASTNode.copySubtree(ast, it)]
+ methodBodyList.addAll(copies)
+ } else if (element instanceof PTargetExpression) {
+ val binding = bindings.get("target")
+ val copies = binding.map[ASTNode.copySubtree(ast, it)]
+ methodBodyList.addAll(copies)
+ } else if (element instanceof PVariableDeclaration) {
+ methodBodyList.add(element.doBuildVariableDeclarationStatement)
+ } else {
+ methodBodyList.add(element.doBuild)
+ }
+ }
+
+ if (methodBodyList.size == 1 && methodBodyList.head instanceof Block) {
+ method.body = (methodBodyList.head as Block)
+ } else {
+ block.statements.addAll(methodBodyList)
+ method.body = block
+ }
+ method
+ }
+
+ //variable declaration builder
+ def private doBuildVariableDeclarationStatement(PVariableDeclaration varDecl) {
+ val fragment = ast.newVariableDeclarationFragment
+
+ //adding variable name
+ if(varDecl.metaName !== null) {
+ fragment.name.identifier = nameBindings.get((varDecl.metaName as PMetaVariable).name)
+ } else {
+ fragment.name.identifier = varDecl.name
+ }
+
+ val newVar = ast.newVariableDeclarationStatement(fragment)
+
+ //adding variable type
+ if(varDecl.type !== null) {
+ newVar.type = Utils.getTypeFromId(typeReferenceQueue.remove, ast)
+ } else {
+ val name = (varDecl.metaType as PMetaVariable).name
+ newVar.type = ASTNode.copySubtree(ast, typeBindings.get(name) as ASTNode) as Type
+ }
+ newVar
+ }
+
+
+ //field declaration builder
+ def private dispatch doBuild(PVariableDeclaration varDecl) {
+ val fragment = ast.newVariableDeclarationFragment
+
+ //adding field name
+ if(varDecl.metaName !== null) {
+ fragment.name.identifier = nameBindings.get( (varDecl.metaName as PMetaVariable).name )
+ } else {
+ fragment.name.identifier = varDecl.name
+ }
+
+ val newField = ast.newFieldDeclaration(fragment)
+
+ //adding field visibility
+ if (varDecl.metaVisibility !== null) {
+ val metaVarName = (varDecl.metaVisibility as PMetaVariable).name
+ switch visibilityBindings.get(metaVarName) {
+ case PUBLIC: newField.modifiers().add(ast.newModifier(ModifierKeyword.PUBLIC_KEYWORD))
+ case PRIVATE: newField.modifiers().add(ast.newModifier(ModifierKeyword.PRIVATE_KEYWORD))
+ case PROTECTED: newField.modifiers().add(ast.newModifier(ModifierKeyword.PROTECTED_KEYWORD))
+ default: {}
+ }
+ } else {
+ switch varDecl.visibility {
+ case PUBLIC: newField.modifiers().add(ast.newModifier(ModifierKeyword.PUBLIC_KEYWORD))
+ case PRIVATE: newField.modifiers().add(ast.newModifier(ModifierKeyword.PRIVATE_KEYWORD))
+ case PROTECTED: newField.modifiers().add(ast.newModifier(ModifierKeyword.PROTECTED_KEYWORD))
+ default: {}
+ }
+ }
+
+ //adding field type
+ if(varDecl.type !== null) {
+ newField.type = Utils.getTypeFromId(typeReferenceQueue.remove, ast)
+ } else {
+ val name = (varDecl.metaType as PMetaVariable).name
+ newField.type = ASTNode.copySubtree(ast, typeBindings.get(name)) as Type
+ }
+
+ newField
+ }
+
+ //method invocation (with expression) builder
+ def private dispatch ASTNode doBuild(PMemberFeatureCall featureCall) {
+ val methodInv = ast.newMethodInvocation
+
+ //adding method invocation name
+ if (featureCall.feature !== null) {
+ methodInv.name.identifier = featureCall.feature
+ } else {
+ val name = (featureCall.metaFeature as PMetaVariable).name
+ methodInv.name.identifier = nameBindings.get(name)
+ }
+
+ //adding method invocation arguments
+ if(featureCall.memberCallArguments !== null) {
+ val argumentList = argumentBindings.get((featureCall.memberCallArguments as PMetaVariable).name)
+ for (argument : argumentList) {
+ val expression = ASTNode.copySubtree(ast, argument)
+ methodInv.arguments.add(expression)
+ }
+ }
+
+ //adding method invocation expression
+ val buildInvocationExpression = featureCall.memberCallTarget.doBuild
+ methodInv.expression = buildInvocationExpression as Expression
+
+ val statement = ast.newExpressionStatement(methodInv)
+ statement
+ }
+
+ //method invocation (without expression) builder
+ // This function is intended for method invocation without expression. Not to be confused with field access. (Field access don't have parantheses at the end)
+ def private dispatch doBuild(PFeatureCall featureCall) {
+ val methodInv = ast.newMethodInvocation
+
+ //adding method invocation name
+ methodInv.name.identifier = featureCall.feature
+
+ //adding method arguments
+ if(featureCall.featureCallArguments !== null) {
+ val argumentList = argumentBindings.get((featureCall.featureCallArguments as PMetaVariable).name)
+ for (argument : argumentList) {
+ val expression = ASTNode.copySubtree(ast, argument)
+ methodInv.arguments.add(expression)
+ }
+ }
+
+ val statement = ast.newExpressionStatement(methodInv)
+ statement
+ }
+
+ //return statement builder
+ def private dispatch ASTNode doBuild(PReturnExpression returnExpr) {
+ val returnStatement = ast.newReturnStatement
+
+ if(returnExpr.expression !== null && returnExpr.expression instanceof PMetaVariable) {
+ val expression = bindings.get((returnExpr.expression as PMetaVariable).name)
+ println(expression.head.class)
+ if (expression.head instanceof Expression) {
+ val copy = ASTNode.copySubtree(ast, expression.head) as Expression
+ returnStatement.expression = copy
+ }
+ }
+ returnStatement
+ }
+
+ //block builder
+ def private dispatch doBuild(PBlockExpression blockPattern) {
val block = ast.newBlock
-
val builtStatements = blockPattern.expressions.doBuildPatterns
block.statements.addAll(builtStatements)
-
- return block
+ block
}
-
- def private doBuildPatterns(List patterns) {
+
+ def private List doBuildPatterns(List patterns) {
patterns.map[doBuild].filterNull.toList
}
-
}
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/api/patterns/PatternMatcher.xtend b/hu.elte.refjava.lang/src/hu/elte/refjava/api/patterns/PatternMatcher.xtend
index 845f6b2..c44ad14 100644
--- a/hu.elte.refjava.lang/src/hu/elte/refjava/api/patterns/PatternMatcher.xtend
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/api/patterns/PatternMatcher.xtend
@@ -1,67 +1,555 @@
package hu.elte.refjava.api.patterns
import hu.elte.refjava.lang.refJava.PBlockExpression
+import hu.elte.refjava.lang.refJava.PConstructorCall
import hu.elte.refjava.lang.refJava.PExpression
+import hu.elte.refjava.lang.refJava.PMemberFeatureCall
import hu.elte.refjava.lang.refJava.PMetaVariable
+import hu.elte.refjava.lang.refJava.PMethodDeclaration
+import hu.elte.refjava.lang.refJava.PTargetExpression
+import hu.elte.refjava.lang.refJava.PVariableDeclaration
import hu.elte.refjava.lang.refJava.Pattern
+import hu.elte.refjava.lang.refJava.Visibility
+import java.util.ArrayList
import java.util.List
import java.util.Map
+import java.util.Queue
import org.eclipse.jdt.core.dom.ASTNode
import org.eclipse.jdt.core.dom.Block
+import org.eclipse.jdt.core.dom.ClassInstanceCreation
+import org.eclipse.jdt.core.dom.ExpressionStatement
+import org.eclipse.jdt.core.dom.FieldDeclaration
+import org.eclipse.jdt.core.dom.MethodDeclaration
+import org.eclipse.jdt.core.dom.MethodInvocation
+import org.eclipse.jdt.core.dom.Modifier
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration
+import org.eclipse.jdt.core.dom.Type
+import org.eclipse.jdt.core.dom.VariableDeclarationFragment
+import org.eclipse.jdt.core.dom.VariableDeclarationStatement
+import org.eclipse.xtext.EcoreUtil2
+import org.eclipse.jdt.core.dom.Expression
+import hu.elte.refjava.lang.refJava.PFeatureCall
+import hu.elte.refjava.lang.refJava.PReturnExpression
+import org.eclipse.jdt.core.dom.ReturnStatement
class PatternMatcher {
-
+
+ ArrayList modifiedTarget
val Pattern pattern
Map> bindings = newHashMap
-
+ Map nameBindings
+ Map typeBindings
+ Map> parameterBindings
+ Map visibilityBindings
+ Map> argumentBindings
+ Queue typeReferenceQueue
+
new(Pattern pattern) {
this.pattern = pattern
}
-
+
def getBindings() {
bindings
}
+
+ def getModifiedTarget() {
+ modifiedTarget
+ }
+
+ def match(Pattern targetPattern, List extends ASTNode> target, Map nameBindings, Map typeBindings, Map> parameterBindings, Map visibilityBindings, Map> argumentBindings, String typeRefString) {
+ bindings.clear
+ this.nameBindings = nameBindings
+ this.typeBindings = typeBindings
+ this.parameterBindings = parameterBindings
+ this.visibilityBindings = visibilityBindings
+ this.argumentBindings = argumentBindings
+
+ if (typeRefString !== null) {
+ val tmp = typeRefString.split("\\|")
+ this.typeReferenceQueue = newLinkedList
+ this.typeReferenceQueue.addAll(tmp)
+ }
+ return doMatchChildren(targetPattern.patterns, target)
+ }
- def match(List extends ASTNode> target) {
+ //this function gets called during the matching
+ def match(List extends ASTNode> target, Map nameBindings, Map typeBindings, Map> parameterBindings, Map visibilityBindings, Map> argumentBindings, String typeRefString) {
+ this.nameBindings = nameBindings
+ this.typeBindings = typeBindings
+ this.parameterBindings = parameterBindings
+ this.visibilityBindings = visibilityBindings
+ this.argumentBindings = argumentBindings
+
+ if (typeRefString !== null) {
+ val tmp = typeRefString.split("\\|")
+ this.typeReferenceQueue = newLinkedList
+ this.typeReferenceQueue.addAll(tmp)
+ }
+
bindings.clear
- return doMatchChildren(pattern.patterns, target)
+ modifiedTarget = newArrayList
+ modifiedTarget.addAll(target)
+
+ val patterns = pattern.patterns
+ val isTargetExists = EcoreUtil2.getAllContentsOfType(pattern, PTargetExpression).size > 0
+ if (!isTargetExists) {
+ doMatchChildren(patterns, target)
+ } else {
+ doMatchChildrenWithTarget(patterns, target)
+ }
}
+ ///////////////////////
+ // doMatch overloads //
+ ///////////////////////
def private dispatch doMatch(PMetaVariable metaVar, ASTNode anyNode) {
bindings.put(metaVar.name, #[anyNode])
- return true
+ true
}
-
+
+ def private dispatch doMatch(PMetaVariable multiMetavar, List nodes) {
+ if(multiMetavar.multi) {
+ bindings.put(multiMetavar.name, nodes)
+ true
+ }
+ }
+
def private dispatch boolean doMatch(PBlockExpression blockPattern, Block block) {
doMatchChildren(blockPattern.expressions, block.statements)
}
+
+ //constructor call matching
+ def private dispatch boolean doMatch(PConstructorCall constCall, ClassInstanceCreation classInstance) {
+
+ //matching constructor call name
+ var boolean nameCheck
+ if (constCall.metaName !== null) {
+ val name = nameBindings.get((constCall.metaName as PMetaVariable).name)
+ if (name === null) {
+ val className = classInstance.type.toString
+ nameBindings.put((constCall.metaName as PMetaVariable).name, className)
+ nameCheck = true
+ } else {
+ nameCheck = name == classInstance.type.toString
+ }
+ } else {
+ nameCheck = constCall.name == classInstance.type.toString
+ }
+
+ //matching constructor call's methods
+ var boolean anonClassCheck
+ if (classInstance.anonymousClassDeclaration !== null && constCall.elements !== null) {
+ anonClassCheck = doMatchChildren(constCall.elements, classInstance.anonymousClassDeclaration.bodyDeclarations)
+ } else {
+ anonClassCheck = true
+ }
+
+ return nameCheck && anonClassCheck
+ }
+
+ //method matching
+ def private dispatch boolean doMatch(PMethodDeclaration pMethodDecl, MethodDeclaration methodDecl) {
+
+ //matching method name
+ var boolean nameCheck
+ if(pMethodDecl.prefix.metaName !== null) {
+ val name = nameBindings.get((pMethodDecl.prefix.metaName as PMetaVariable).name)
+ if (name === null) {
+ val methodName = methodDecl.name.identifier
+ nameBindings.put((pMethodDecl.prefix.metaName as PMetaVariable).name, methodName)
+ nameCheck = true
+ } else {
+ nameCheck = name == methodDecl.name.identifier
+ }
+ } else {
+ nameCheck = pMethodDecl.prefix.name == methodDecl.name.identifier
+ }
+
+ //matching method visibility
+ var boolean visibilityCheck
+ val modifiers = methodDecl.getModifiers
+ if (pMethodDecl.prefix.metaVisibility !== null) {
+ val metaVarName = (pMethodDecl.prefix.metaVisibility as PMetaVariable).name
+ if (visibilityBindings.get(metaVarName) === null) {
+ switch modifiers {
+ case Modifier.isPublic(modifiers) : visibilityBindings.put(metaVarName, Visibility.PUBLIC)
+ case Modifier.isPrivate(modifiers) : visibilityBindings.put(metaVarName, Visibility.PRIVATE)
+ case Modifier.isProtected(modifiers) : visibilityBindings.put(metaVarName, Visibility.PROTECTED)
+ default : visibilityBindings.put(metaVarName, Visibility.PACKAGE)
+ }
+ visibilityCheck = true
+ } else {
+ switch visibilityBindings.get(metaVarName) {
+ case PUBLIC: visibilityCheck = Modifier.isPublic(modifiers)
+ case PRIVATE: visibilityCheck = Modifier.isPrivate(modifiers)
+ case PROTECTED: visibilityCheck = Modifier.isProtected(modifiers)
+ default: visibilityCheck = modifiers.bitwiseAnd(Modifier.PROTECTED) == 0 && modifiers.bitwiseAnd(Modifier.PRIVATE) == 0 && modifiers.bitwiseAnd(Modifier.PUBLIC) == 0
+ }
+ }
+ } else {
+ switch pMethodDecl.prefix.visibility {
+ case PUBLIC: visibilityCheck = Modifier.isPublic(modifiers)
+ case PRIVATE: visibilityCheck = Modifier.isPrivate(modifiers)
+ case PROTECTED: visibilityCheck = Modifier.isProtected(modifiers)
+ default: visibilityCheck = modifiers.bitwiseAnd(Modifier.PROTECTED) == 0 && modifiers.bitwiseAnd(Modifier.PRIVATE) == 0 && modifiers.bitwiseAnd(Modifier.PUBLIC) == 0
+ }
+ }
+
+ //matching method return value
+ var boolean returnCheck
+ if(pMethodDecl.prefix.metaType !== null) {
+ val type = typeBindings.get((pMethodDecl.prefix.metaType as PMetaVariable).name)
+ if (type === null) {
+ val returnType = methodDecl.returnType2
+ typeBindings.put((pMethodDecl.prefix.metaType as PMetaVariable).name, returnType)
+ returnCheck = true
+ } else {
+ returnCheck = type.resolveBinding.qualifiedName == methodDecl.returnType2.resolveBinding.qualifiedName
+ }
+ } else {
+ returnCheck = methodDecl.returnType2.resolveBinding.qualifiedName == typeReferenceQueue.remove
+ }
+
+ //matching method parameters
+ var boolean parameterCheck = true
+ if (pMethodDecl.parameters.size > 0) {
+ if (pMethodDecl.parameters.size != methodDecl.parameters.size) {
+ parameterCheck = false
+ } else {
+ val argIt = pMethodDecl.parameters.iterator
+ val paramIt = (methodDecl.parameters as List).iterator
+ while(argIt.hasNext && parameterCheck) {
+ val arg = argIt.next
+ val param = paramIt.next
+ parameterCheck = param.name.identifier == arg.name && param.type.resolveBinding.qualifiedName == typeReferenceQueue.remove
+ }
+ }
+ } else if (pMethodDecl.metaParameters !== null) {
+ val metaVar = pMethodDecl.metaParameters as PMetaVariable
+ val parameters = parameterBindings.get((pMethodDecl.metaParameters as PMetaVariable).name)
+ if (parameters === null) {
+ parameterBindings.put(metaVar.name, methodDecl.parameters)
+ parameterCheck = true
+ } else {
+ if (parameters.size != methodDecl.parameters.size) {
+ parameterCheck = false
+ } else {
+ val it1 = parameters.iterator
+ val it2 = (methodDecl.parameters as List).iterator
+ while(it1.hasNext && parameterCheck) {
+ val param1 = it1.next
+ val param2 = it2.next
+ parameterCheck = param1.name.identifier == param2.name.identifier && param1.type.resolveBinding.qualifiedName == param2.type.resolveBinding.qualifiedName
+ }
+ }
+ }
+ } else {
+ parameterCheck = methodDecl.parameters.size == 0
+ }
+
+ //matching method body
+ val boolean bodyCheck = doMatch(pMethodDecl.body, methodDecl.body)
+
+ return nameCheck && visibilityCheck && parameterCheck && returnCheck && bodyCheck
+ }
+
+ //method invocation matching (with expression)
+ def private dispatch boolean doMatch(PMemberFeatureCall featureCall, ExpressionStatement expStatement) {
+ if (expStatement.expression instanceof MethodInvocation) {
+ val methodInv = expStatement.expression as MethodInvocation
+
+ //matching method invocation name
+ var boolean nameCheck
+ if (featureCall.feature !== null) {
+ nameCheck = featureCall.feature == methodInv.name.identifier
+ } else {
+ val name = nameBindings.get((featureCall.metaFeature as PMetaVariable).name)
+ if (name === null) {
+ val methodName = methodInv.name.identifier
+ nameBindings.put((featureCall.metaFeature as PMetaVariable).name, methodName)
+ nameCheck = true
+ } else {
+ nameCheck = name == methodInv.name.identifier
+ }
+ }
+
+ //matching method invocation parameters
+ var boolean argumentCheck = true
+ if(featureCall.memberCallArguments !== null) {
+ val metaVarName = (featureCall.memberCallArguments as PMetaVariable).name
+ if (argumentBindings.get(metaVarName) === null) {
+ argumentBindings.put(metaVarName, methodInv.arguments)
+ argumentCheck = true
+ } else {
+ val arguments = argumentBindings.get(metaVarName)
+ if(methodInv.arguments.size != arguments.size) {
+ argumentCheck = false
+ } else {
+ //currently we can't assign values to argument-binding meta variables
+ argumentCheck = true
+ }
+ }
+ } else {
+ argumentCheck = methodInv.arguments.size == 0
+ }
+
+ //matching method invocation expression
+ val boolean expressionCheck = doMatch(featureCall.memberCallTarget, methodInv.expression)
+
+ return nameCheck && argumentCheck && expressionCheck
+ } else {
+ return false
+ }
+ }
+
+
+ //method invocation matching (without expression)
+ def private dispatch boolean doMatch(PFeatureCall featureCall, ExpressionStatement expStatement) {
+ if (expStatement.expression instanceof MethodInvocation) {
+ val methodInv = expStatement.expression as MethodInvocation
+
+ //matching method invocation name
+ var boolean nameCheck
+ if (featureCall.feature !== null) {
+ nameCheck = featureCall.feature == methodInv.name.identifier
+ } else {
+ val name = nameBindings.get((featureCall.metaFeature as PMetaVariable).name)
+ if (name === null) {
+ val methodName = methodInv.name.identifier
+ nameBindings.put((featureCall.metaFeature as PMetaVariable).name, methodName)
+ nameCheck = true
+ } else {
+ nameCheck = name == methodInv.name.identifier
+ }
+ }
+
+ //matching method invocation parameters
+ var boolean argumentCheck = true
+ if(featureCall.featureCallArguments !== null) {
+ val metaVarName = (featureCall.featureCallArguments as PMetaVariable).name
+ if (argumentBindings.get(metaVarName) === null) {
+ argumentBindings.put(metaVarName, methodInv.arguments)
+ argumentCheck = true
+ } else {
+ val arguments = argumentBindings.get(metaVarName)
+ if(methodInv.arguments.size != arguments.size) {
+ argumentCheck = false
+ } else {
+ //currently we can't assign values to argument-binding meta variables
+ argumentCheck = true
+ }
+ }
+ } else {
+ argumentCheck = methodInv.arguments.size == 0
+ }
+
+ return nameCheck && argumentCheck
+ } else {
+ return false
+ }
+ }
+
+ //variable declaration matching
+ def private dispatch boolean doMatch(PVariableDeclaration varDecl, VariableDeclarationStatement varDeclStatement) {
+
+ //matching variable declaration name
+ var boolean nameCheck
+ if (varDecl.metaName !== null) {
+ val name = nameBindings.get((varDecl.metaName as PMetaVariable).name)
+ if(name === null) {
+ val varName = (varDeclStatement.fragments.head as VariableDeclarationFragment).name.identifier
+ nameBindings.put((varDecl.metaName as PMetaVariable).name, varName)
+ nameCheck = true
+ } else {
+ nameCheck = name == (varDeclStatement.fragments.head as VariableDeclarationFragment).name.identifier
+ }
+ } else {
+ nameCheck = varDecl.name == (varDeclStatement.fragments.head as VariableDeclarationFragment).name.identifier
+ }
+
+ //matching variable declaration type
+ var boolean typeCheck
+ if(varDecl.type !== null) {
+ typeCheck = varDeclStatement.type.resolveBinding.qualifiedName == typeReferenceQueue.remove
+ } else {
+ val type = typeBindings.get((varDecl.metaType as PMetaVariable).name)
+ if (type === null) {
+ val varType = varDeclStatement.type
+ typeBindings.put((varDecl.metaType as PMetaVariable).name, varType)
+ typeCheck = true
+ } else {
+ typeCheck = type.resolveBinding.qualifiedName == varDeclStatement.type.resolveBinding.qualifiedName
+ }
+ }
+
+ return nameCheck && typeCheck
+ }
+
+ //field declaration matching
+ def private dispatch boolean doMatch(PVariableDeclaration varDecl, FieldDeclaration fieldDecl) {
+
+ //matching field declaration name
+ var boolean nameCheck
+ if (varDecl.metaName !== null) {
+ val name = nameBindings.get((varDecl.metaName as PMetaVariable).name)
+ if (name === null) {
+ val fieldName = (fieldDecl.fragments.head as VariableDeclarationFragment).name.identifier
+ nameBindings.put((varDecl.metaName as PMetaVariable).name, fieldName)
+ nameCheck = true
+ } else {
+ nameCheck = name == (fieldDecl.fragments.head as VariableDeclarationFragment).name.identifier
+ }
+ } else {
+ nameCheck = varDecl.name == (fieldDecl.fragments.head as VariableDeclarationFragment).name.identifier
+ }
+
+ //matching field declaration visibility
+ var boolean visibilityCheck
+ val modifiers = fieldDecl.getModifiers
+ if (varDecl.metaVisibility !== null) {
+ val metaVarName = (varDecl.metaVisibility as PMetaVariable).name
+ if (visibilityBindings.get(metaVarName) === null) {
+ switch modifiers {
+ case Modifier.isPublic(modifiers) : visibilityBindings.put(metaVarName, Visibility.PUBLIC)
+ case Modifier.isPrivate(modifiers) : visibilityBindings.put(metaVarName, Visibility.PRIVATE)
+ case Modifier.isProtected(modifiers) : visibilityBindings.put(metaVarName, Visibility.PROTECTED)
+ default : visibilityBindings.put(metaVarName, Visibility.PACKAGE)
+ }
+ visibilityCheck = true
+ } else {
+ switch visibilityBindings.get(metaVarName) {
+ case PUBLIC: visibilityCheck = Modifier.isPublic(modifiers)
+ case PRIVATE: visibilityCheck = Modifier.isPrivate(modifiers)
+ case PROTECTED: visibilityCheck = Modifier.isProtected(modifiers)
+ default: visibilityCheck = modifiers.bitwiseAnd(Modifier.PROTECTED) == 0 && modifiers.bitwiseAnd(Modifier.PRIVATE) == 0 && modifiers.bitwiseAnd(Modifier.PUBLIC) == 0
+ }
+ }
+ } else {
+ switch varDecl.visibility {
+ case PUBLIC: visibilityCheck = Modifier.isPublic(modifiers)
+ case PRIVATE: visibilityCheck = Modifier.isPrivate(modifiers)
+ case PROTECTED: visibilityCheck = Modifier.isProtected(modifiers)
+ default: visibilityCheck = modifiers.bitwiseAnd(Modifier.PROTECTED) == 0 && modifiers.bitwiseAnd(Modifier.PRIVATE) == 0 && modifiers.bitwiseAnd(Modifier.PUBLIC) == 0
+ }
+ }
+
+ //matching field declaration type
+ var boolean typeCheck
+ if(varDecl.type !== null) {
+ typeCheck = fieldDecl.type.resolveBinding.qualifiedName == typeReferenceQueue.remove
+ } else {
+ val type = typeBindings.get((varDecl.metaType as PMetaVariable).name)
+ if (type === null) {
+ val fieldType = fieldDecl.type
+ typeBindings.put((varDecl.metaType as PMetaVariable).name, fieldType)
+ typeCheck = true
+ } else {
+ typeCheck = type.resolveBinding.qualifiedName == fieldDecl.type.resolveBinding.qualifiedName
+ }
+ }
+ return nameCheck && visibilityCheck && typeCheck
+ }
+
+ def private dispatch boolean doMatch(PReturnExpression returnExpr, ReturnStatement returnStatement) {
+
+ var boolean expressionCheck
+ if (returnExpr.expression !== null) {
+ val exp = returnExpr.expression
+ if(exp instanceof PMetaVariable) {
+ bindings.put(exp.name, #[returnStatement.expression])
+ expressionCheck = true
+ } else {
+ expressionCheck = false
+ }
+ } else {
+ expressionCheck = true
+ }
+ expressionCheck
+ }
+
+
def private dispatch doMatch(PExpression anyOtherPattern, ASTNode anyOtherNode) {
false
}
-
+
+ ///////////////////////
+ // children matching //
+ ///////////////////////
def private doMatchChildren(List patterns, List extends ASTNode> nodes) {
- if (patterns.size == 1 && patterns.head instanceof PMetaVariable) {
- val metaVar = patterns.head as PMetaVariable
- if (metaVar.isMulti) {
- bindings.put(metaVar.name, nodes)
- return true
- }
+ if (patterns.size == 1 && patterns.head instanceof PMetaVariable && (patterns.head as PMetaVariable).multi) {
+ bindings.put("target", nodes)
+ bindings.put((patterns.head as PMetaVariable).name , nodes)
+ return true
}
-
- if (patterns.size != nodes.size) {
+
+ if (!patterns.exists[it instanceof PMetaVariable && (it as PMetaVariable).multi] && nodes.size != patterns.size) {
return false
}
-
- val pIt = patterns.iterator
+
val nIt = nodes.iterator
- while (pIt.hasNext) {
- if (!doMatch(pIt.next, nIt.next)) {
- return false
+ for (var int i = 0; i < patterns.size; i++) {
+ if( !(patterns.get(i) instanceof PMetaVariable) || !(patterns.get(i) as PMetaVariable).multi ) {
+ if (!doMatch(patterns.get(i), nIt.next)) {
+ return false
+ }
+ } else {
+ val preMultiMetavar = patterns.take(i).size
+ val postMultiMetavar = patterns.drop(i + 1).size
+ var List matchingNodes = newArrayList
+ var int j = 0
+
+ while (j != nodes.size - (preMultiMetavar + postMultiMetavar) ) {
+ matchingNodes.add(nIt.next)
+ j++
+ }
+
+ if(!doMatch(patterns.get(i), matchingNodes)) {
+ return false
+ }
}
}
-
- return true
+ bindings.put("target", nodes)
+ true
}
+
+ def private doMatchChildrenWithTarget(List patterns, List extends ASTNode> selectedNodes) {
+ if (patterns.size == 1 && patterns.head instanceof PTargetExpression) {
+ bindings.put("target", selectedNodes)
+ return true
+ }
+
+ var List preTargetExpression = patterns.clone.takeWhile[ !(it instanceof PTargetExpression) ].toList
+ var List postTargetExpression = patterns.clone.reverse.takeWhile[ !(it instanceof PTargetExpression) ].toList.reverse
+
+ val List targetEnvironment = newArrayList
+ // If the user use the program as we intended, the selectedNodes.head.parent will be direct contents of a block.
+ targetEnvironment.addAll( (selectedNodes.head.parent as Block).statements )
+
+ var List preSelectedNodes = (targetEnvironment as List).clone.takeWhile[ it != selectedNodes.head ].toList
+ var List postSelectedNodes = (targetEnvironment as List).clone.reverse.takeWhile[ it != selectedNodes.last ].toList.reverse
+
+ var boolean pre
+ var boolean post
+ if (!preTargetExpression.exists[ it instanceof PMetaVariable && (it as PMetaVariable).isMulti] ) {
+ val preSelectedNodesToMatch = preSelectedNodes.clone.reverse.take(preTargetExpression.size).toList.reverse
+ pre = doMatchChildren(preTargetExpression, preSelectedNodesToMatch)
+ modifiedTarget.addAll(0, preSelectedNodesToMatch)
+ } else {
+ pre = doMatchChildren(preTargetExpression, preSelectedNodes)
+ modifiedTarget.addAll(0, preSelectedNodes)
+ }
+
+ if (!postTargetExpression.exists[ it instanceof PMetaVariable && (it as PMetaVariable).isMulti] ) {
+ val postSelectedNodesToMatch = postSelectedNodes.clone.take(postTargetExpression.size).toList
+ post = doMatchChildren(postTargetExpression, postSelectedNodesToMatch)
+ modifiedTarget.addAll(postSelectedNodesToMatch)
+ } else {
+ post = doMatchChildren(postTargetExpression, postSelectedNodes)
+ modifiedTarget.addAll(postSelectedNodes)
+ }
+ bindings.put("target", selectedNodes)
+ return pre && post
+ }
}
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/api/patterns/PatternParser.xtend b/hu.elte.refjava.lang/src/hu/elte/refjava/api/patterns/PatternParser.xtend
index c77d89b..b7cd406 100644
--- a/hu.elte.refjava.lang/src/hu/elte/refjava/api/patterns/PatternParser.xtend
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/api/patterns/PatternParser.xtend
@@ -10,11 +10,10 @@ import org.eclipse.xtext.resource.XtextResource
import org.eclipse.xtext.resource.XtextResourceSet
class PatternParser {
-
@Inject static XtextResourceSet resourceSet
static Resource resource
static boolean initialized = false
-
+
def static parse(String patternString) {
if (!initialized) {
resourceSet.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE)
@@ -25,15 +24,13 @@ class PatternParser {
if (resource.loaded) {
resource.unload
}
-
+
val paddedPatternString = '''package p; local refactoring l() «patternString» ~ nothing'''
val inputStream = new ByteArrayInputStream(paddedPatternString.bytes)
- resource.load(inputStream, resourceSet.loadOptions)
-
+ resource.load(inputStream, resourceSet.loadOptions)
val file = resource.contents.head as File
val refact = file.refactorings.head as SchemeInstanceRule
-
+
return refact.matchingPattern
- }
-
+ }
}
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/api/patterns/Utils.xtend b/hu.elte.refjava.lang/src/hu/elte/refjava/api/patterns/Utils.xtend
new file mode 100644
index 0000000..6ea8601
--- /dev/null
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/api/patterns/Utils.xtend
@@ -0,0 +1,151 @@
+package hu.elte.refjava.api.patterns
+
+import hu.elte.refjava.lang.refJava.Pattern
+import org.eclipse.jdt.core.dom.AST
+import org.eclipse.jdt.core.dom.ASTNode
+import org.eclipse.jdt.core.dom.CompilationUnit
+import org.eclipse.jdt.core.dom.FieldDeclaration
+import org.eclipse.jdt.core.dom.MethodDeclaration
+import org.eclipse.jdt.core.dom.PrimitiveType
+import org.eclipse.jdt.core.dom.TypeDeclaration
+import org.eclipse.jdt.core.dom.VariableDeclarationStatement
+import org.eclipse.xtext.EcoreUtil2
+import org.eclipse.xtext.common.types.JvmTypeReference
+import org.eclipse.jdt.core.dom.ASTParser
+import org.eclipse.jdt.core.ICompilationUnit
+import org.eclipse.jface.text.IDocument
+import org.eclipse.jdt.core.dom.Assignment
+import org.eclipse.jdt.core.dom.Block
+import hu.elte.refjava.lang.refJava.PExpression
+import hu.elte.refjava.lang.refJava.PMemberFeatureCall
+import hu.elte.refjava.lang.refJava.PConstructorCall
+import hu.elte.refjava.lang.refJava.PMethodDeclaration
+import hu.elte.refjava.lang.refJava.PVariableDeclaration
+
+class Utils {
+
+ def static getTypeFromId(String id, AST ast) {
+
+ val primitiveTypes = newArrayList("byte", "short", "char", "int", "long", "float", "double", "boolean", "void")
+
+ if(primitiveTypes.contains(id)) {
+ //primitive type
+ return ast.newPrimitiveType(PrimitiveType.toCode(id))
+ } else if (id.contains("[") && id.contains("]")) {
+ //array type
+ val char openingSymbol = '['
+ val char closingSymbol = ']'
+ var String type = ""
+ var int dimension = 0
+ for(var int i = 0; i < id.length; i++) {
+ if( id.charAt(i).identityEquals(openingSymbol) ) {
+ dimension++
+ } else if ( !id.charAt(i).identityEquals(openingSymbol) && !id.charAt(i).identityEquals(closingSymbol)) {
+ type += id.charAt(i)
+ }
+ }
+ if(primitiveTypes.contains(type)) {
+ //primitive array type
+ return ast.newArrayType(ast.newPrimitiveType(PrimitiveType.toCode(type)), dimension)
+ } else {
+ //simple array type
+ val simpleName = type.split("\\.")
+ return ast.newArrayType(ast.newSimpleType(ast.newSimpleName(simpleName.last)), dimension)
+ }
+ } else {
+ //simple type
+ val simpleName = id.split("\\.").last
+ return ast.newSimpleType(ast.newSimpleName(simpleName))
+ }
+ }
+
+ def static getTypeReferenceString(Pattern pattern) {
+ var String typeReferenceString = ""
+ val types = EcoreUtil2.getAllContentsOfType(pattern, JvmTypeReference)
+ for(type : types) {
+ typeReferenceString = typeReferenceString + type.identifier + "|"
+ }
+ return typeReferenceString
+ }
+
+ def static getTypeDeclaration(ASTNode node) {
+ var tmp = node
+ while (!(tmp instanceof TypeDeclaration)) {
+ tmp = tmp.parent
+ }
+ tmp as TypeDeclaration
+ }
+
+ def static getCompilationUnit(ASTNode node) {
+ var tmp = node
+ while (!(tmp instanceof CompilationUnit)) {
+ tmp = tmp.parent
+ }
+ tmp as CompilationUnit
+ }
+
+ def static getICompilationUnit(ASTNode node) {
+ node.compilationUnit.getJavaElement as ICompilationUnit
+ }
+
+ def static getMethodDeclaration(ASTNode node) {
+ var tmp = node
+ while (!(tmp instanceof MethodDeclaration) && tmp !== null) {
+ tmp = tmp.parent
+ }
+ tmp as MethodDeclaration
+ }
+
+ def static getBlock(ASTNode node) {
+ var tmp = node
+ while (!(tmp instanceof Block) && tmp !== null) {
+ tmp = tmp.parent
+ }
+ tmp as Block
+ }
+
+ def static getFieldDeclaration(ASTNode node) {
+ var tmp = node
+ while (!(tmp instanceof FieldDeclaration) && tmp !== null) {
+ tmp = tmp.parent
+ }
+ tmp as FieldDeclaration
+ }
+
+ def static getVariableDeclaration(ASTNode node) {
+ var tmp = node
+ while (!(tmp instanceof VariableDeclarationStatement) && tmp !== null) {
+ tmp = tmp.parent
+ }
+ tmp as VariableDeclarationStatement
+ }
+
+ def static getAssignment(ASTNode node) {
+ var tmp = node
+ while (!(tmp instanceof Assignment) && tmp !== null) {
+ tmp = tmp.parent
+ }
+ tmp as Assignment
+ }
+
+ def static parseSourceCode(ICompilationUnit iCompUnit) {
+ val parser = ASTParser.newParser(AST.JLS12);
+ parser.resolveBindings = true
+ parser.source = iCompUnit
+ parser.createAST(null) as CompilationUnit
+ }
+
+ def static applyChanges(CompilationUnit compUnit, IDocument document) {
+ compUnit.rewrite(document, null).apply(document)
+ }
+
+ def static isValidLambdaExpression (PExpression expression) {
+ (expression instanceof PMemberFeatureCall)
+ && ((expression as PMemberFeatureCall).memberCallTarget instanceof PConstructorCall)
+ && (((expression as PMemberFeatureCall).memberCallTarget as PConstructorCall).anonInstance)
+ && ((expression as PMemberFeatureCall).memberCallTarget as PConstructorCall).elements.exists[it instanceof PMethodDeclaration]
+ && ((expression as PMemberFeatureCall).memberCallTarget as PConstructorCall).elements.forall[it instanceof PMethodDeclaration || it instanceof PVariableDeclaration]
+ }
+
+
+}
\ No newline at end of file
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/lang/GenerateRefJava.mwe2 b/hu.elte.refjava.lang/src/hu/elte/refjava/lang/GenerateRefJava.mwe2
index d3decd5..2be55a9 100644
--- a/hu.elte.refjava.lang/src/hu/elte/refjava/lang/GenerateRefJava.mwe2
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/lang/GenerateRefJava.mwe2
@@ -11,11 +11,15 @@ Workflow {
project = StandardProjectConfig {
baseName = "hu.elte.refjava.lang"
rootPath = rootPath
-
+
+ runtimeTest = {
+ enabled = true
+ }
+
eclipsePlugin = {
enabled = true
}
-
+
createEclipseMetaData = true
}
@@ -36,6 +40,10 @@ Workflow {
validator = {
generateDeprecationValidation = true
}
+
+ junitSupport = {
+ junitVersion = "5"
+ }
}
}
}
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/lang/RefJava.xtext b/hu.elte.refjava.lang/src/hu/elte/refjava/lang/RefJava.xtext
index 190266a..1e7ff80 100644
--- a/hu.elte.refjava.lang/src/hu/elte/refjava/lang/RefJava.xtext
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/lang/RefJava.xtext
@@ -31,9 +31,22 @@ SchemeInstanceRule:
('in' definitionLocation=InDefinitionLocation)?
definitionPattern=Pattern)?
('when'
- precondition=XExpression)?
+ ('assignment'
+ assignments=AssignmentList)?
+ ('precondition'
+ precondition=XExpression)?
+ )?
+;
+
+AssignmentList:
+ assignment+=MetaVariableAssignment =>(';' assignment+=MetaVariableAssignment)* ';'?
+;
+
+MetaVariableAssignment:
+ {MetaVariableAssignment} metaVariable=PMetaVariable '=' value=XExpression
;
+
enum SchemeType:
LOCAL='local' | BLOCK='block' | LAMBDA='lambda' | CLASS='class'
;
@@ -55,8 +68,12 @@ CompositeRefactoringRule:
// Patterns //
//////////////
+enum MetaVariableType:
+ CODE='#' | NAME='name#' | TYPE='type#' | PARAMETER='parameter#' | VISIBILITY='visibility#' | ARGUMENT='argument#'
+;
+
PMetaVariable returns PExpression:
- {PMetaVariable} '#' name=ID multi?='..'?
+ {PMetaVariable} type=MetaVariableType name=ID multi?='..'?
;
Pattern:
@@ -72,8 +89,8 @@ PExpressionOrVarDeclaration returns PExpression:
PDeclaration returns PExpression:
PVariableDeclaration (
{PMethodDeclaration.prefix=current} '(' (
- arguments+=FullJvmFormalParameter (',' arguments+=FullJvmFormalParameter)* | metaArguments=PMetaVariable
- )? ')' (body=PBlockExpression | metaBody=PMetaVariable)
+ parameters+=FullJvmFormalParameter (',' parameters+=FullJvmFormalParameter)* | metaParameters=PMetaVariable
+ )? ')' (body=PBlockExpression)
)?
;
@@ -81,7 +98,7 @@ PVariableDeclaration returns PVariableDeclaration:
=>({PVariableDeclaration} ( // =>: global, see PExpressionOrVarDeclaration->...->PFeatureCall
(visibility=Visibility | metaVisibility=PMetaVariable)? // for methods
(type=JvmTypeReference | metaType=PMetaVariable)
- (name=ValidID | metaName=PMetaVariable)
+ (name=ValidID | metaName=PMetaVariable)
)) ('=' right=PExpression)?
;
@@ -93,11 +110,12 @@ PExpression returns PExpression:
PMemberFeatureCall
;
+
PMemberFeatureCall returns PExpression:
PPrimaryExpression (
=>({PMemberFeatureCall.memberCallTarget=current} ".")
(feature=IdOrSuper | metaFeature=PMetaVariable) (
- =>'(' (memberCallArguments+=PExpression (',' memberCallArguments+=PExpression)*)? ')'
+ =>'(' memberCallArguments=PMetaVariable? ')' //currently restricted to PMetaVariable, should be PExpression
)?
)*
;
@@ -114,8 +132,8 @@ PPrimaryExpression returns PExpression
;
PConstructorCall returns PExpression:
- {PConstructorCall} 'new' constructor=[types::JvmConstructor|QualifiedName]
- =>'(' (arguments+=PExpression (',' arguments+=PExpression)*)? ')' (
+ {PConstructorCall} 'new' (name=ValidID | metaName=PMetaVariable)
+ =>'(' arguments=PMetaVariable? ')' ( //currently restricted to PMetaVariable, should be PExpression
anonInstance?='{' (elements+=PDeclaration =>(';' elements+=PDeclaration)* ';'?)? '}'
// =>: local, distinguishes semicolons
)?
@@ -130,17 +148,17 @@ PBlockExpression returns PExpression:
PFeatureCall returns PExpression:
{PFeatureCall} (
- feature=IdOrSuper (
- =>'(' (featureCallArguments+=PExpression (',' featureCallArguments+=PExpression)*)? ')'
+ feature=IdOrSuper (
+ =>'(' featureCallArguments=PMetaVariable? ')' //currently restricted to PMetaVariable, should be PExpression
)?
) | (
- metaFeature=PMetaVariable
- =>'(' (featureCallArguments+=PExpression (',' featureCallArguments+=PExpression)*)? ')'
+ metaFeature=PMetaVariable
+ =>'(' featureCallArguments=PMetaVariable? ')' //currently restricted to PMetaVariable, should be PExpression
)
;
PReturnExpression returns PExpression:
- {PReturnExpression} 'return' (->expression=PExpression)?
+ {PReturnExpression} 'return' (->expression=PMetaVariable)?
;
PTargetExpression returns PExpression:
@@ -174,10 +192,15 @@ XPrimaryExpression returns xbase::XExpression
| XTryCatchFinallyExpression
| XParenthesizedExpression
| MetaVariable
+ | TargetExpression
;
MetaVariable returns xbase::XExpression:
- {MetaVariable} '#' name=ID multi?='..'?
+ {MetaVariable} type=MetaVariableType name=ID multi?='..'?
+;
+
+TargetExpression returns xbase::XExpression:
+ {TargetExpression} 'target'
;
@Override
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/lang/compiler/RefJavaCompiler.xtend b/hu.elte.refjava.lang/src/hu/elte/refjava/lang/compiler/RefJavaCompiler.xtend
index 768ce37..1599511 100644
--- a/hu.elte.refjava.lang/src/hu/elte/refjava/lang/compiler/RefJavaCompiler.xtend
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/lang/compiler/RefJavaCompiler.xtend
@@ -1,6 +1,8 @@
package hu.elte.refjava.lang.compiler
import hu.elte.refjava.lang.refJava.MetaVariable
+import hu.elte.refjava.lang.refJava.MetaVariableType
+import hu.elte.refjava.lang.refJava.TargetExpression
import org.eclipse.xtext.xbase.XExpression
import org.eclipse.xtext.xbase.compiler.XbaseCompiler
import org.eclipse.xtext.xbase.compiler.output.ITreeAppendable
@@ -11,6 +13,8 @@ class RefJavaCompiler extends XbaseCompiler {
switch expression {
MetaVariable:
expression.toJavaStatement(builder)
+ TargetExpression:
+ expression.toJavaStatement(builder)
default:
super.doInternalToJavaStatement(expression, builder, isReferenced)
}
@@ -19,21 +23,40 @@ class RefJavaCompiler extends XbaseCompiler {
def void toJavaStatement(MetaVariable metaVar, ITreeAppendable it) {
// do nothing, a metavariable is strictly an expression
}
+
+ def void toJavaStatement(TargetExpression targetExpr, ITreeAppendable it) {
+ // do nothing, a metavariable is strictly an expression
+ }
override protected internalToConvertedExpression(XExpression expression, ITreeAppendable builder) {
switch expression {
MetaVariable:
expression.toJavaExpression(builder)
+ TargetExpression:
+ expression.toJavaExpression(builder)
default:
super.internalToConvertedExpression(expression, builder)
}
}
def dispatch void toJavaExpression(MetaVariable metaVar, ITreeAppendable it) {
- append('''bindings.get("«metaVar.name»")''')
- if (!metaVar.multi) {
- append(".get(0)")
+ if(metaVar.type == MetaVariableType.CODE) {
+ append('''bindings.get("«metaVar.name»")''')
+ if (!metaVar.multi) {
+ append(".get(0)")
+ }
+ } else if (metaVar.type == MetaVariableType.NAME) {
+ append('''nameBindings.get("«metaVar.name»")''')
+ } else if (metaVar.type == MetaVariableType.TYPE) {
+ append('''typeBindings.get("«metaVar.name»")''')
+ } else if (metaVar.type == MetaVariableType.PARAMETER) {
+ append('''parameterBindings.get("«metaVar.name»")''')
+ } else if (metaVar.type == MetaVariableType.VISIBILITY) {
+ append('''visibilityBindings.get("«metaVar.name»")''')
}
}
-
+
+ def dispatch void toJavaExpression(TargetExpression targetExpr, ITreeAppendable it) {
+ append('''bindings.get("target")''')
+ }
}
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/lang/jvmmodel/RefJavaJvmModelInferrer.xtend b/hu.elte.refjava.lang/src/hu/elte/refjava/lang/jvmmodel/RefJavaJvmModelInferrer.xtend
index 4aec72c..2d92418 100644
--- a/hu.elte.refjava.lang/src/hu/elte/refjava/lang/jvmmodel/RefJavaJvmModelInferrer.xtend
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/lang/jvmmodel/RefJavaJvmModelInferrer.xtend
@@ -1,9 +1,18 @@
package hu.elte.refjava.lang.jvmmodel
import com.google.inject.Inject
+import hu.elte.refjava.api.BlockRefactoring
+import hu.elte.refjava.api.ClassRefactoring
+import hu.elte.refjava.api.LambdaRefactoring
import hu.elte.refjava.api.LocalRefactoring
+import hu.elte.refjava.api.patterns.Utils
+import hu.elte.refjava.lang.refJava.MetaVariableType
+import hu.elte.refjava.lang.refJava.PMetaVariable
+import hu.elte.refjava.lang.refJava.Pattern
import hu.elte.refjava.lang.refJava.SchemeInstanceRule
import hu.elte.refjava.lang.refJava.SchemeType
+import java.util.List
+import org.eclipse.jdt.core.dom.Type
import org.eclipse.xtext.common.types.JvmVisibility
import org.eclipse.xtext.naming.IQualifiedNameProvider
import org.eclipse.xtext.serializer.ISerializer
@@ -16,15 +25,106 @@ class RefJavaJvmModelInferrer extends AbstractModelInferrer {
@Inject extension IQualifiedNameProvider
@Inject extension ISerializer
@Inject extension JvmTypesBuilder
-
+
def dispatch infer(SchemeInstanceRule rule, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
acceptor.accept(rule.toClass(rule.fullyQualifiedName)) [
superTypes += rule.type.toSuperType.typeRef
-
+
+ //type parsing doesn't work..
+ val typeRefGetter = [ Pattern pattern |
+ if (pattern !== null) {
+ Utils.getTypeReferenceString(pattern)
+ } else {
+ ""
+ }
+ ]
+
+ val matchingTypeReferenceString = typeRefGetter.apply(rule.matchingPattern)
+ val replacementTypeReferenceString = typeRefGetter.apply(rule.replacementPattern)
+ val targetTypeReferenceString = typeRefGetter.apply(rule.targetPattern)
+ val definitionTypeReferenceString = typeRefGetter.apply(rule.definitionPattern)
+
members += rule.toConstructor [
body = '''super("«rule.matchingPattern.serialize.trim»", "«rule.replacementPattern.serialize.trim»");'''
]
-
+
+ val endl = System.getProperty("line.separator");
+ var String callings = ""
+ if(rule.assignments !== null) {
+ for (assignment : rule.assignments.assignment) {
+ val metaVar = assignment.metaVariable as PMetaVariable
+ val metaVarName = (assignment.metaVariable as PMetaVariable).name
+
+ if (metaVar.type == MetaVariableType.NAME) {
+ members += rule.toMethod("valueof_name_" + metaVarName, typeof(String).typeRef) [
+ visibility = JvmVisibility.PRIVATE
+ body = assignment.value
+ ]
+ callings = callings + "set_name_" + metaVarName + "();" + endl
+ members += rule.toMethod("set_name_" + metaVarName, typeof(void).typeRef) [
+ visibility = JvmVisibility.PRIVATE
+ body = '''nameBindings.put("«metaVarName»", valueof_name_«metaVarName»());'''
+ ]
+ } else if (metaVar.type == MetaVariableType.TYPE) {
+ members += rule.toMethod("valueof_type_" + metaVarName, typeof(Type).typeRef) [
+ visibility = JvmVisibility.PRIVATE
+ body = assignment.value
+ ]
+ callings = callings + "set_type_" + metaVarName + "();" + endl
+ members += rule.toMethod("set_type_" + metaVarName, typeof(void).typeRef) [
+ visibility = JvmVisibility.PRIVATE
+ body = '''typeBindings.put("«metaVarName»", valueof_type_«metaVarName»());'''
+ ]
+ } else if (metaVar.type == MetaVariableType.PARAMETER) {
+ members += rule.toMethod("valueof_parameter_" + metaVarName, typeof(List).typeRef) [
+ visibility = JvmVisibility.PRIVATE
+ body = assignment.value
+ ]
+ callings = callings + "set_parameter_" + metaVarName + "();" + endl
+ members += rule.toMethod("set_parameter_" + metaVarName, typeof(void).typeRef) [
+ visibility = JvmVisibility.PRIVATE
+ body = '''parameterBindings.put("«metaVarName»", valueof_parameter_«metaVarName»());'''
+ ]
+ } else if (metaVar.type == MetaVariableType.VISIBILITY) {
+ members += rule.toMethod("valueof_visibility_" + metaVarName, typeof(List).typeRef) [
+ visibility = JvmVisibility.PRIVATE
+ body = assignment.value
+ ]
+ callings = callings + "set_visibility_" + metaVarName + "();" + endl
+ members += rule.toMethod("set_visibility_" + metaVarName, typeof(void).typeRef) [
+ visibility = JvmVisibility.PRIVATE
+ body = '''visibilityBindings.put("«metaVarName»", valueof_visibility_«metaVarName»());'''
+ ]
+ } else if(metaVar.type == MetaVariableType.ARGUMENT) {
+ members += rule.toMethod("valueof_argument_" + metaVarName, typeof(List).typeRef) [
+ visibility = JvmVisibility.PRIVATE
+ body = assignment.value
+ ]
+ callings = callings + "set_argument_" + metaVarName + "();" + endl
+ members += rule.toMethod("set_argument_" + metaVarName, typeof(void).typeRef) [
+ visibility = JvmVisibility.PRIVATE
+ body = '''argumentBindings.put("«metaVarName»", valueof_argument_«metaVarName»());'''
+ ]
+ }
+ }
+ }
+
+ if(rule.definitionPattern !== null && (rule.type == SchemeType.LAMBDA || rule.type == SchemeType.CLASS) ) {
+ callings = callings + '''super.definitionString = "«rule.definitionPattern.serialize.trim»";'''+ endl
+ }
+
+ val finalCallings = callings + endl
+ if (finalCallings.length > 2 || matchingTypeReferenceString.length > 0 || replacementTypeReferenceString.length > 0 || targetTypeReferenceString.length > 0 || definitionTypeReferenceString.length > 0) {
+ members += rule.toMethod("setMetaVariables", typeof(void).typeRef) [
+ //annotations += annotationRef(Override)
+ visibility = JvmVisibility.PROTECTED
+ body = '''«finalCallings»super.matchingTypeReferenceString = "«matchingTypeReferenceString»";
+super.replacementTypeReferenceString = "«replacementTypeReferenceString»";
+super.targetTypeReferenceString = "«targetTypeReferenceString»";
+super.definitionTypeReferenceString = "«definitionTypeReferenceString»";'''
+ ]
+ }
+
if (rule.precondition !== null) {
members += rule.toMethod("instanceCheck", Boolean.TYPE.typeRef) [
visibility = JvmVisibility.PRIVATE
@@ -37,11 +137,24 @@ class RefJavaJvmModelInferrer extends AbstractModelInferrer {
body = '''return super.check() && instanceCheck();'''
]
}
+
+ if (rule.targetPattern !== null) {
+ members += rule.toMethod("safeTargetCheck", Boolean.TYPE.typeRef) [
+ annotations += annotationRef(Override)
+ visibility = JvmVisibility.PROTECTED
+ body = '''return super.targetCheck("«rule.targetPattern.serialize.trim»");'''
+ ]
+ }
]
}
def private toSuperType(SchemeType it) {
- LocalRefactoring
+ switch it {
+ case LOCAL : LocalRefactoring
+ case BLOCK : BlockRefactoring
+ case LAMBDA : LambdaRefactoring
+ case CLASS : ClassRefactoring
+ }
}
}
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/lang/scoping/RefJavaImplicitlyImportedFeatures.xtend b/hu.elte.refjava.lang/src/hu/elte/refjava/lang/scoping/RefJavaImplicitlyImportedFeatures.xtend
index f1e1572..201bf59 100644
--- a/hu.elte.refjava.lang/src/hu/elte/refjava/lang/scoping/RefJavaImplicitlyImportedFeatures.xtend
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/lang/scoping/RefJavaImplicitlyImportedFeatures.xtend
@@ -1,12 +1,11 @@
package hu.elte.refjava.lang.scoping
-import org.eclipse.xtext.xbase.scoping.batch.ImplicitlyImportedFeatures
import hu.elte.refjava.api.Check
+import org.eclipse.xtext.xbase.scoping.batch.ImplicitlyImportedFeatures
class RefJavaImplicitlyImportedFeatures extends ImplicitlyImportedFeatures {
override protected getStaticImportClasses() {
(super.getStaticImportClasses() + #[Check]).toList
}
-
}
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/lang/typesystem/RefJavaTypeComputer.xtend b/hu.elte.refjava.lang/src/hu/elte/refjava/lang/typesystem/RefJavaTypeComputer.xtend
index ac90341..2bc95d8 100644
--- a/hu.elte.refjava.lang/src/hu/elte/refjava/lang/typesystem/RefJavaTypeComputer.xtend
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/lang/typesystem/RefJavaTypeComputer.xtend
@@ -1,8 +1,13 @@
package hu.elte.refjava.lang.typesystem
import hu.elte.refjava.lang.refJava.MetaVariable
+import hu.elte.refjava.lang.refJava.MetaVariableType
+import hu.elte.refjava.lang.refJava.TargetExpression
import java.util.List
import org.eclipse.jdt.core.dom.ASTNode
+import org.eclipse.jdt.core.dom.Expression
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration
+import org.eclipse.jdt.core.dom.Type
import org.eclipse.xtext.xbase.typesystem.computation.ITypeComputationState
import org.eclipse.xtext.xbase.typesystem.computation.XbaseTypeComputer
import org.eclipse.xtext.xbase.typesystem.references.ParameterizedTypeReference
@@ -10,17 +15,44 @@ import org.eclipse.xtext.xbase.typesystem.references.ParameterizedTypeReference
class RefJavaTypeComputer extends XbaseTypeComputer {
def dispatch computeTypes(MetaVariable metaVar, ITypeComputationState state) {
- val astNodeType = getTypeForName(ASTNode, state)
-
- val type = if (!metaVar.multi) {
- astNodeType
- } else {
+ if (metaVar.type == MetaVariableType.CODE) {
+ val astNodeType = getTypeForName(ASTNode, state)
+ val type = if (!metaVar.multi) {
+ astNodeType
+ } else {
+ val listType = getTypeForName(List, state) as ParameterizedTypeReference
+ listType.addTypeArgument(astNodeType)
+ listType
+ }
+ state.acceptActualType(type)
+
+ } else if (metaVar.type == MetaVariableType.NAME) {
+ val stringType = getTypeForName(String, state)
+ state.acceptActualType(stringType)
+
+ } else if (metaVar.type == MetaVariableType.TYPE) {
+ val typeType = getTypeForName(Type, state)
+ state.acceptActualType(typeType)
+
+ } else if (metaVar.type == MetaVariableType.PARAMETER) {
+ val parameterType = getTypeForName(SingleVariableDeclaration, state)
+ val listType = getTypeForName(List, state) as ParameterizedTypeReference
+ listType.addTypeArgument(parameterType)
+ state.acceptActualType(listType)
+
+ } else if(metaVar.type == MetaVariableType.ARGUMENT) {
+ val expressionType = getTypeForName(Expression, state)
val listType = getTypeForName(List, state) as ParameterizedTypeReference
- listType.addTypeArgument(astNodeType)
- listType
+ listType.addTypeArgument(expressionType)
+ state.acceptActualType(listType)
}
+ }
+ def dispatch computeTypes(TargetExpression targetExpr, ITypeComputationState state) {
+ val astNodeType = getTypeForName(ASTNode, state)
+ val listType = getTypeForName(List, state) as ParameterizedTypeReference
+ listType.addTypeArgument(astNodeType)
+ val type = listType
state.acceptActualType(type)
}
-
}
diff --git a/hu.elte.refjava.lang/src/hu/elte/refjava/lang/validation/RefJavaValidator.xtend b/hu.elte.refjava.lang/src/hu/elte/refjava/lang/validation/RefJavaValidator.xtend
index e55f28a..766ec3e 100644
--- a/hu.elte.refjava.lang/src/hu/elte/refjava/lang/validation/RefJavaValidator.xtend
+++ b/hu.elte.refjava.lang/src/hu/elte/refjava/lang/validation/RefJavaValidator.xtend
@@ -1,7 +1,10 @@
package hu.elte.refjava.lang.validation
import hu.elte.refjava.lang.refJava.MetaVariable
+import hu.elte.refjava.lang.refJava.PBlockExpression
+import hu.elte.refjava.lang.refJava.PExpression
import hu.elte.refjava.lang.refJava.PMetaVariable
+import hu.elte.refjava.lang.refJava.PTargetExpression
import hu.elte.refjava.lang.refJava.RefJavaPackage
import hu.elte.refjava.lang.refJava.SchemeInstanceRule
import org.eclipse.emf.ecore.EAttribute
@@ -10,39 +13,225 @@ import org.eclipse.xtext.EcoreUtil2
import org.eclipse.xtext.validation.Check
import static hu.elte.refjava.lang.refJava.RefJavaPackage.Literals.*
+import hu.elte.refjava.lang.refJava.SchemeType
+import hu.elte.refjava.lang.refJava.PNothingExpression
+import hu.elte.refjava.lang.refJava.PFeatureCall
+import hu.elte.refjava.lang.refJava.PMethodDeclaration
+import hu.elte.refjava.lang.refJava.PVariableDeclaration
+import hu.elte.refjava.lang.refJava.PMemberFeatureCall
+import hu.elte.refjava.lang.refJava.PConstructorCall
+import hu.elte.refjava.lang.refJava.MetaVariableType
+import hu.elte.refjava.api.patterns.Utils
class RefJavaValidator extends AbstractRefJavaValidator {
-
+
@Check
def checkMetaVariableUniqueness(SchemeInstanceRule schemeInstanceRule) {
val matchingMetaVars = EcoreUtil2.getAllContentsOfType(schemeInstanceRule.matchingPattern, PMetaVariable)
matchingMetaVars.forEach [ inspectedMetaVar |
- if (matchingMetaVars.exists[name == inspectedMetaVar.name && it != inspectedMetaVar]) {
+ if (matchingMetaVars.exists[name == inspectedMetaVar.name && type == inspectedMetaVar.type && it != inspectedMetaVar]) {
error("Duplicate metavariable " + inspectedMetaVar.name, inspectedMetaVar,
RefJavaPackage.Literals.PMETA_VARIABLE__NAME)
}
]
}
-
+
@Check
def checkMetaVariableReferences(SchemeInstanceRule schemeInstanceRule) {
val matchingMetaVars = EcoreUtil2.getAllContentsOfType(schemeInstanceRule.matchingPattern, PMetaVariable)
- val metaVarChecker = [ EObject inspectedMetaVar, String inspectedName, boolean inspectedMulti,
+ val metaVarChecker = [ EObject inspectedMetaVar, String inspectedName, MetaVariableType inspectedType, boolean inspectedMulti,
EAttribute nameFeature, EAttribute multiFeature |
val referencedMetaVar = matchingMetaVars.findFirst[name == inspectedName]
- if (referencedMetaVar === null) {
+ if (inspectedType == MetaVariableType.CODE && referencedMetaVar === null) {
error("Metavariable " + inspectedName + " cannot be resolved", inspectedMetaVar, nameFeature)
- } else if (inspectedMulti != referencedMetaVar.multi) {
+ } else if (inspectedType == MetaVariableType.CODE && inspectedMulti != referencedMetaVar.multi) {
error("Metavariable " + inspectedName + " has wrong multiplicity", inspectedMetaVar, multiFeature)
}
]
EcoreUtil2.getAllContentsOfType(schemeInstanceRule.replacementPattern, PMetaVariable).forEach [
- metaVarChecker.apply(it, name, multi, PMETA_VARIABLE__NAME, PMETA_VARIABLE__MULTI)
+ metaVarChecker.apply(it, name, type, multi, PMETA_VARIABLE__NAME, PMETA_VARIABLE__MULTI)
]
EcoreUtil2.getAllContentsOfType(schemeInstanceRule.precondition, MetaVariable).forEach [
- metaVarChecker.apply(it, name, multi, META_VARIABLE__NAME, META_VARIABLE__MULTI)
+ metaVarChecker.apply(it, name, type, multi, META_VARIABLE__NAME, META_VARIABLE__MULTI)
]
}
+
+ @Check
+ def targetPatternChecker(SchemeInstanceRule schemeInstanceRule) {
+ if (schemeInstanceRule.type == SchemeType.LOCAL && schemeInstanceRule.targetPattern !== null) {
+
+ error("A local refactoring scheme cannot have a target closure.", schemeInstanceRule, SCHEME_INSTANCE_RULE__TYPE)
+
+ } else {
+ if (schemeInstanceRule.targetPattern !== null) {
+ if (EcoreUtil2.getAllContentsOfType(schemeInstanceRule.targetPattern, PTargetExpression) !== null) {
+ EcoreUtil2.getAllContentsOfType(schemeInstanceRule.targetPattern, PTargetExpression).forEach[
+ error("The target pattern cannot contain a target expression.", it, PTARGET_EXPRESSION.getEStructuralFeature(0))
+ ]
+ }
+ }
+ }
+ }
+
+ //checks the attribute-binding meta variable type correctness
+ @Check
+ def metaVariableTypeCorrectnessChecker(SchemeInstanceRule schemeInstanceRule) {
+ schemeInstanceRule.matchingPattern.patterns.forEach[hasCorrectMetaVariableTypes]
+ schemeInstanceRule.replacementPattern.patterns.forEach[hasCorrectMetaVariableTypes]
+ schemeInstanceRule.targetPattern.patterns.forEach[hasCorrectMetaVariableTypes]
+ schemeInstanceRule.definitionPattern.patterns.forEach[hasCorrectMetaVariableTypes]
+ }
+
+ def void hasCorrectMetaVariableTypes(PExpression expression) {
+ if (expression instanceof PMethodDeclaration) {
+ val method = expression as PMethodDeclaration
+ if (method.metaParameters !== null && (method.metaParameters as PMetaVariable).type != MetaVariableType.PARAMETER) {
+ error("The type of the meta variable should be 'parameter' here.", method.metaParameters, PMETA_VARIABLE__TYPE)
+ }
+ method.prefix.hasCorrectMetaVariableTypes
+ } else if (expression instanceof PVariableDeclaration) {
+ val varDecl = expression as PVariableDeclaration
+ if(varDecl.metaName !== null && (varDecl.metaName as PMetaVariable).type != MetaVariableType.NAME) {
+ error("The type of the meta variable should be 'name' here.", varDecl.metaName, PMETA_VARIABLE__TYPE)
+ }
+ if(varDecl.metaType !== null && (varDecl.metaType as PMetaVariable).type != MetaVariableType.TYPE) {
+ error("The type of the meta variable should be 'type' here.", varDecl.metaType, PMETA_VARIABLE__TYPE)
+ }
+ if(varDecl.metaVisibility !== null && (varDecl.metaVisibility as PMetaVariable).type != MetaVariableType.VISIBILITY) {
+ error("The type of the meta variable should be 'visibility' here.", varDecl.metaVisibility, PMETA_VARIABLE__TYPE)
+ }
+ } else if (expression instanceof PMemberFeatureCall) {
+ val memberFeatureCall = expression as PMemberFeatureCall
+ if(memberFeatureCall.metaFeature !== null && (memberFeatureCall.metaFeature as PMetaVariable).type != MetaVariableType.NAME) {
+ error("The type of the meta variable should be 'name' here.", memberFeatureCall.metaFeature, PMETA_VARIABLE__TYPE)
+ }
+ if(memberFeatureCall.memberCallArguments !== null && (memberFeatureCall.memberCallArguments as PMetaVariable).type != MetaVariableType.ARGUMENT) {
+ error("The type of the meta variable should be 'argument' here.", memberFeatureCall.memberCallArguments, PMETA_VARIABLE__TYPE)
+ }
+ memberFeatureCall.memberCallTarget.hasCorrectMetaVariableTypes
+ } else if (expression instanceof PConstructorCall) {
+ val constructorCall = expression as PConstructorCall
+ if (constructorCall.metaName !== null && (constructorCall.metaName as PMetaVariable).type != MetaVariableType.NAME) {
+ error("The type of the meta variable should be 'name' here.", constructorCall.metaName, PMETA_VARIABLE__TYPE)
+ }
+ if (constructorCall.arguments !== null && (constructorCall.arguments as PMetaVariable).type != MetaVariableType.ARGUMENT) {
+ error("The type of the meta variable should be 'argument' here.", constructorCall.arguments, PMETA_VARIABLE__TYPE)
+ }
+ if (constructorCall.anonInstance) {
+ constructorCall.elements.forEach[hasCorrectMetaVariableTypes]
+ }
+ } else if (expression instanceof PBlockExpression) {
+ val block = expression as PBlockExpression
+ block.expressions.forEach[hasCorrectMetaVariableTypes]
+ } else if (expression instanceof PFeatureCall) {
+ val featureCall = expression as PFeatureCall
+ if(featureCall.metaFeature !== null && (featureCall.metaFeature as PMetaVariable).type != MetaVariableType.NAME) {
+ error("The type of the meta variable should be 'name' here.", featureCall.metaFeature, PMETA_VARIABLE__TYPE)
+ }
+ if(featureCall.featureCallArguments !== null && (featureCall.featureCallArguments as PMetaVariable).type != MetaVariableType.ARGUMENT) {
+ error("The type of the meta variable should be 'argument' here.", featureCall.featureCallArguments, PMETA_VARIABLE__TYPE)
+ }
+ }
+ }
+
+ @Check
+ def parameterAndArgumentMetaVariableMultiplicity(SchemeInstanceRule schemeInstanceRule) {
+ EcoreUtil2.getAllContentsOfType(schemeInstanceRule.matchingPattern, PMetaVariable).forEach[hasCorrectMultiplicity]
+ EcoreUtil2.getAllContentsOfType(schemeInstanceRule.replacementPattern, PMetaVariable).forEach[hasCorrectMultiplicity]
+ EcoreUtil2.getAllContentsOfType(schemeInstanceRule.targetPattern, PMetaVariable).forEach[hasCorrectMultiplicity]
+ EcoreUtil2.getAllContentsOfType(schemeInstanceRule.definitionPattern, PMetaVariable).forEach[hasCorrectMultiplicity]
+ }
+
+ def hasCorrectMultiplicity(PMetaVariable metaVar) {
+ if(metaVar.type == MetaVariableType.PARAMETER && !metaVar.multi) {
+ error("A parameter-binding meta variable should always have multiplicity.", metaVar, PMETA_VARIABLE__MULTI)
+ } else if (metaVar.type == MetaVariableType.ARGUMENT && !metaVar.multi) {
+ error("An argument-binding meta variable should always have multiplicity.", metaVar, PMETA_VARIABLE__MULTI)
+ } else if (metaVar.type == MetaVariableType.NAME && metaVar.multi) {
+ error("A name-binding meta variable cannot have multiplicity.", metaVar, PMETA_VARIABLE__MULTI)
+ } else if (metaVar.type == MetaVariableType.TYPE && metaVar.multi) {
+ error("A type-binding meta variable cannot have multiplicity.", metaVar, PMETA_VARIABLE__MULTI)
+ } else if (metaVar.type == MetaVariableType.VISIBILITY && metaVar.multi) {
+ error("A visibility-binding meta variable cannot have multiplicity.", metaVar, PMETA_VARIABLE__MULTI)
+ }
+ }
+
+
+ //class and lambda refactorings pattern limitations
+ @Check
+ def patternLimitationsChecker(SchemeInstanceRule schemeInstanceRule) {
+ if(schemeInstanceRule.type == SchemeType.CLASS) {
+ if (!(schemeInstanceRule.replacementPattern.patterns.head instanceof PNothingExpression)
+ && !(schemeInstanceRule.replacementPattern.patterns.head instanceof PFeatureCall)
+ || schemeInstanceRule.replacementPattern.patterns.size > 1) {
+
+ error("A class refactoring's replacement pattern can only be either a single nothing expression or a single feature call.",
+ schemeInstanceRule.replacementPattern, PATTERN.getEStructuralFeature(0))
+
+ } else if (schemeInstanceRule.replacementPattern.patterns.head instanceof PNothingExpression
+ && !(schemeInstanceRule.matchingPattern.patterns.head instanceof PMethodDeclaration)
+ && !(schemeInstanceRule.matchingPattern.patterns.head instanceof PVariableDeclaration)
+ || schemeInstanceRule.matchingPattern.patterns.size > 1) {
+ error("The matching pattern can only be either a single method declaration or a single variable declaration, if the replacement pattern is a nothing expression.",
+ schemeInstanceRule.matchingPattern, PATTERN.getEStructuralFeature(0))
+ }
+ } else if (schemeInstanceRule.type == SchemeType.LAMBDA) {
+
+ if (!Utils.isValidLambdaExpression(schemeInstanceRule.replacementPattern.patterns.head) || schemeInstanceRule.replacementPattern.patterns.size > 1) {
+ error("A lambda refactoring's replacement pattern can only be a single valid lambda expression.
+Example: new F() { public void apply() { } }.apply()", schemeInstanceRule.replacementPattern, PATTERN.getEStructuralFeature(0))
+
+ } else if (schemeInstanceRule.matchingPattern.patterns.exists[Utils.isValidLambdaExpression(it)] && schemeInstanceRule.matchingPattern.patterns.size > 1) {
+
+ error("The matching pattern can be either a single lambda expression, or a pattern that doesn't contains a lambda expression.", schemeInstanceRule.replacementPattern, PATTERN.getEStructuralFeature(0))
+
+ } else if (!((schemeInstanceRule.replacementPattern.patterns.head as PMemberFeatureCall).memberCallTarget as PConstructorCall).elements.exists[
+ it instanceof PMethodDeclaration && ((it as PMethodDeclaration).prefix.name == (schemeInstanceRule.replacementPattern.patterns.head as PMemberFeatureCall).feature
+ && ((it as PMethodDeclaration).prefix.metaName as PMetaVariable).name == ((schemeInstanceRule.replacementPattern.patterns.head as PMemberFeatureCall).metaFeature as PMetaVariable).name)]) {
+
+ error("The feature call's name can only be an existing method inside the lambda expression.", schemeInstanceRule.replacementPattern, PATTERN.getEStructuralFeature(0))
+
+ } else if (Utils.isValidLambdaExpression(schemeInstanceRule.matchingPattern.patterns.head) && !((schemeInstanceRule.matchingPattern.patterns.head as PMemberFeatureCall).memberCallTarget as PConstructorCall).elements.exists[
+ it instanceof PMethodDeclaration && ((it as PMethodDeclaration).prefix.name == (schemeInstanceRule.matchingPattern.patterns.head as PMemberFeatureCall).feature
+ && ((it as PMethodDeclaration).prefix.metaName as PMetaVariable).name == ((schemeInstanceRule.matchingPattern.patterns.head as PMemberFeatureCall).metaFeature as PMetaVariable).name)]) {
+
+ error("The feature call's name can only be an existing method inside the lambda expression.", schemeInstanceRule.matchingPattern, PATTERN.getEStructuralFeature(0))
+
+ } else if (Utils.isValidLambdaExpression(schemeInstanceRule.matchingPattern.patterns.head) && schemeInstanceRule.matchingPattern.patterns.size > 1) {
+ error("The matching pattern's length can only be single, if the matching pattern is meant to be a lambda expression.", schemeInstanceRule.matchingPattern, PATTERN.getEStructuralFeature(0))
+ }
+ }
+ }
+
+ @Check
+ def multiMetavariableCountValidation(SchemeInstanceRule schemeInstanceRule) {
+ val matchingPatterns = schemeInstanceRule.matchingPattern.patterns
+ val targetExpressions = EcoreUtil2.getAllContentsOfType(schemeInstanceRule.matchingPattern, PTargetExpression)
+ if(targetExpressions.size != 0) {
+
+ if (targetExpressions.size > 1) {
+ targetExpressions.forEach[error("Two or more target expression within the same matching pattern doesn't make sense.", it, PTARGET_EXPRESSION.getEStructuralFeature(0) )]
+ }
+ val preTargetExpressions = matchingPatterns.clone.takeWhile[ !(it instanceof PTargetExpression)]
+ val postTargetExpressions = matchingPatterns.clone.reverse.takeWhile[ !(it instanceof PTargetExpression)]
+ multiMetavarCountChecker(preTargetExpressions)
+ multiMetavarCountChecker(postTargetExpressions)
+
+ } else {
+ multiMetavarCountChecker(matchingPatterns)
+ }
+ }
+
+ def void multiMetavarCountChecker(Iterable expressions) {
+ val multiMetavars = expressions.filter[it instanceof PMetaVariable && (it as PMetaVariable).multi]
+ val blocks = expressions.filter[it instanceof PBlockExpression]
+ if (multiMetavars.size > 1) {
+ multiMetavars.forEach[error("Two or more metavariable with multiplicity in the same scope doesn't make sense.
+If the matching pattern has a target expression, then there cannot be two or more
+metavariable with multiplicity before, and after the target expression.", it, PMETA_VARIABLE__MULTI)]
+ }
+ blocks.forEach[multiMetavarCountChecker( (it as PBlockExpression).expressions )]
+ }
}
diff --git a/hu.elte.refjava.update/.project b/hu.elte.refjava.update/.project
new file mode 100644
index 0000000..530e02b
--- /dev/null
+++ b/hu.elte.refjava.update/.project
@@ -0,0 +1,17 @@
+
+
+ hu.elte.refjava.update
+
+
+
+
+
+ org.eclipse.pde.UpdateSiteBuilder
+
+
+
+
+
+ org.eclipse.pde.UpdateSiteNature
+
+
diff --git a/hu.elte.refjava.update/artifacts.jar b/hu.elte.refjava.update/artifacts.jar
new file mode 100644
index 0000000..89a7702
Binary files /dev/null and b/hu.elte.refjava.update/artifacts.jar differ
diff --git a/hu.elte.refjava.update/content.jar b/hu.elte.refjava.update/content.jar
new file mode 100644
index 0000000..c7721a0
Binary files /dev/null and b/hu.elte.refjava.update/content.jar differ
diff --git a/hu.elte.refjava.update/features/hu.elte.refjava.feature_1.0.0.202005151427.jar b/hu.elte.refjava.update/features/hu.elte.refjava.feature_1.0.0.202005151427.jar
new file mode 100644
index 0000000..7e94b85
Binary files /dev/null and b/hu.elte.refjava.update/features/hu.elte.refjava.feature_1.0.0.202005151427.jar differ
diff --git a/hu.elte.refjava.update/plugins/hu.elte.refjava.control_1.0.0.202005151427.jar b/hu.elte.refjava.update/plugins/hu.elte.refjava.control_1.0.0.202005151427.jar
new file mode 100644
index 0000000..755c8dd
Binary files /dev/null and b/hu.elte.refjava.update/plugins/hu.elte.refjava.control_1.0.0.202005151427.jar differ
diff --git a/hu.elte.refjava.update/plugins/hu.elte.refjava.lang.ide_1.0.0.202005151427.jar b/hu.elte.refjava.update/plugins/hu.elte.refjava.lang.ide_1.0.0.202005151427.jar
new file mode 100644
index 0000000..5b3a1bd
Binary files /dev/null and b/hu.elte.refjava.update/plugins/hu.elte.refjava.lang.ide_1.0.0.202005151427.jar differ
diff --git a/hu.elte.refjava.update/plugins/hu.elte.refjava.lang.ui_1.0.0.202005151427.jar b/hu.elte.refjava.update/plugins/hu.elte.refjava.lang.ui_1.0.0.202005151427.jar
new file mode 100644
index 0000000..4c36fd5
Binary files /dev/null and b/hu.elte.refjava.update/plugins/hu.elte.refjava.lang.ui_1.0.0.202005151427.jar differ
diff --git a/hu.elte.refjava.update/plugins/hu.elte.refjava_1.0.0.202005151427.jar b/hu.elte.refjava.update/plugins/hu.elte.refjava_1.0.0.202005151427.jar
new file mode 100644
index 0000000..34ade4b
Binary files /dev/null and b/hu.elte.refjava.update/plugins/hu.elte.refjava_1.0.0.202005151427.jar differ
diff --git a/hu.elte.refjava.update/site.xml b/hu.elte.refjava.update/site.xml
new file mode 100644
index 0000000..dc6e238
--- /dev/null
+++ b/hu.elte.refjava.update/site.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+