Bug 457617

Summary: [xbase][refactoring] Renaming a static method replaces references with fully qualified name
Product: [Modeling] TMF Reporter: Lorenzo Bettini <lorenzo.bettini>
Component: XtextAssignee: Project Inbox <tmf.xtext-inbox>
Status: NEW --- QA Contact:
Severity: normal    
Priority: P3 CC: christian.dietrich.opensource
Version: 2.7.3Keywords: triaged
Target Milestone: ---   
Hardware: All   
OS: All   
Whiteboard:

Description Lorenzo Bettini CLA 2015-01-15 10:45:55 EST
In an Xbase language, when you refactor an element inferred to a static method, existing references are replaced with the fully qualified name of the renamed element.  This happens in Xtend as well.

For example, given this Xtend program

package mypackage

class MyXtendFile {
	def static void foo() {
		foo()
	}
}

select "foo", start refactoring, e.g, as "bar" and press ENTER; after refactoring the modified program is

package mypackage

class MyXtendFile {
	def static void bar() {
		mypackage.MyXtendFile.bar()
	}
}
Comment 1 Lorenzo Bettini CLA 2015-01-15 10:53:07 EST
Some additional comments (see also https://www.eclipse.org/forums/index.php/t/943988/): I tried to debug a little bit what is going on during refactoring; I don't know whether this can help, but I found suspicious what happens in this method

RefactoringScopeReferenceSerializer

public String getCrossRefText(EObject owner, CrossReference crossref, EObject target,
	RefTextEvaluator refTextEvaluator, ITextRegion linkTextRegion, StatusWrapper status) {
	try {
		final EReference ref = GrammarUtil.getReference(crossref, owner.eClass());
		final IScope scope = scopeProvider.getScope(owner, ref);
...
		Iterable<IEObjectDescription> descriptionsForCrossRef = scope.getElements(target);
		String bestRefText = null;
		for (IEObjectDescription desc : descriptionsForCrossRef) {
			try {
				String unconvertedRefText = qualifiedNameConverter.toString(desc.getName());
				String convertedRefText = valueConverter.toString(unconvertedRefText, ruleName);
				if (refTextEvaluator.isValid(desc) && (bestRefText == null || refTextEvaluator.isBetterThan(convertedRefText, bestRefText)))
						bestRefText = convertedRefText;

the call to refTextEvaluator.isValid(desc) returns false; this happens because

return new RefTextEvaluator() {

public boolean isValid(IEObjectDescription newTarget) {
	IScope scope = linkingScopeProvider.getScope(referringElement, reference);
	IEObjectDescription element = scope.getSingleElement(newTarget.getName());
	// TODO here we need to simulate linking with the new name instead of the old name
	if(element instanceof IIdentifiableElementDescription) {
		IIdentifiableElementDescription casted = (IIdentifiableElementDescription) element;
		if(!casted.isVisible() || !casted.isValidStaticState())
			return false;
		}

casted.isValidStaticState() returns

false since its implicitReceiverType is NOT null (it is the inferred Java class).