Skip to content

Commit

Permalink
[ui] Add quick fix that adds "uses" of capacities when methods were n…
Browse files Browse the repository at this point in the history
…ot found.

close #974

Signed-off-by: Stéphane Galland <galland@arakhne.org>
  • Loading branch information
gallandarakhneorg committed Apr 25, 2021
1 parent d381fbd commit 450d578
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 0 deletions.
Expand Up @@ -33,6 +33,7 @@
import com.google.inject.Injector;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.xtend.core.jvmmodel.IXtendJvmAssociations;
Expand All @@ -44,6 +45,7 @@
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.common.types.util.AnnotationLookup;
import org.eclipse.xtext.common.types.util.jdt.IJavaElementFinder;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import org.eclipse.xtext.naming.IQualifiedNameProvider;
import org.eclipse.xtext.naming.QualifiedName;
Expand Down Expand Up @@ -81,6 +83,7 @@
import io.sarl.lang.ui.quickfix.acceptors.AnnotationRemoveModification;
import io.sarl.lang.ui.quickfix.acceptors.BehaviorUnitGuardRemoveModification;
import io.sarl.lang.ui.quickfix.acceptors.CapacityReferenceRemoveModification;
import io.sarl.lang.ui.quickfix.acceptors.CapacityUseAddModification;
import io.sarl.lang.ui.quickfix.acceptors.ExtendedTypeRemoveModification;
import io.sarl.lang.ui.quickfix.acceptors.FiredEventRemoveModification;
import io.sarl.lang.ui.quickfix.acceptors.ImplementedTypeRemoveModification;
Expand Down Expand Up @@ -148,6 +151,9 @@ public class SARLQuickfixProvider extends XtendQuickfixProvider {
@Inject
private JvmTypesBuilder typeBuilder;

@Inject
private IJavaElementFinder javaElementFinder;

/** Replies if the given code is for a ignorable warning.
*
* @param code the code of the warning.
Expand Down Expand Up @@ -246,6 +252,15 @@ public ReplacingAppendable.Factory getAppendableFactory() {
return this.appendableFactory;
}

/** Replies the Java element finder.
*
* @return the finder.
* @since 0.12
*/
public IJavaElementFinder getJavaElementFinder() {
return this.javaElementFinder;
}

/** Replies the project utilities.
*
* @return the utilities.
Expand Down Expand Up @@ -986,4 +1001,11 @@ public void fixManualInlineDefinition(final Issue issue, IssueResolutionAcceptor
AnnotationRemoveModification.accept(this, issue, acceptor);
}

@Override
protected void createLinkingIssueQuickfixes(Issue issue, IssueResolutionAcceptor issueResolutionAcceptor,
IXtextDocument xtextDocument, XtextResource resource, EObject referenceOwner, EReference unresolvedReference) throws Exception {
CapacityUseAddModification.accept(this, issue, referenceOwner, issueResolutionAcceptor);
super.createLinkingIssueQuickfixes(issue, issueResolutionAcceptor, xtextDocument, resource, referenceOwner, unresolvedReference);
}

}
@@ -0,0 +1,227 @@
/*
* $Id$
*
* SARL is an general-purpose agent programming language.
* More details on http://www.sarl.io
*
* Copyright (C) 2014-2021 the original authors or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.sarl.lang.ui.quickfix.acceptors;

import java.text.MessageFormat;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.eclipse.jdt.internal.core.NamedMember;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
import org.eclipse.jdt.internal.ui.text.correction.IProposalRelevance;
import org.eclipse.xtend.core.xtend.XtendTypeDeclaration;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.common.types.JvmDeclaredType;
import org.eclipse.xtext.common.types.JvmGenericType;
import org.eclipse.xtext.common.types.JvmIdentifiableElement;
import org.eclipse.xtext.common.types.JvmMember;
import org.eclipse.xtext.common.types.JvmOperation;
import org.eclipse.xtext.common.types.JvmType;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.ui.editor.model.IXtextDocument;
import org.eclipse.xtext.ui.editor.model.edit.IModificationContext;
import org.eclipse.xtext.ui.editor.quickfix.IssueResolutionAcceptor;
import org.eclipse.xtext.util.IAcceptor;
import org.eclipse.xtext.util.Strings;
import org.eclipse.xtext.validation.Issue;
import org.eclipse.xtext.xbase.XAbstractFeatureCall;
import org.eclipse.xtext.xbase.ui.contentassist.ReplacingAppendable;

import io.sarl.lang.core.Capacity;
import io.sarl.lang.sarl.SarlAgent;
import io.sarl.lang.sarl.SarlBehavior;
import io.sarl.lang.sarl.SarlSkill;
import io.sarl.lang.ui.quickfix.SARLQuickfixProvider;
import io.sarl.lang.util.OutParameter;
import io.sarl.lang.util.Utils;

/**
* Add a capacity use.
*
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
* @since 0.12
*/
public final class CapacityUseAddModification extends SARLSemanticModification {

private final JvmDeclaredType capacity;

/** Constructor.
*
* @param capacity is the capacity.
*/
private CapacityUseAddModification(JvmDeclaredType capacity) {
this.capacity = capacity;
}

private static boolean isEquivalentMethodName(String currentName, String declaredName) {
return Strings.equal(currentName, declaredName);
}

private static void findCandidateTypesWithOperation(String methodSimpleName, JvmGenericType genericType, IAcceptor<JvmGenericType> acceptor) {
for (final JvmMember jvmMember : genericType.getMembers()) {
if (jvmMember instanceof JvmOperation) {
final JvmOperation operation = (JvmOperation) jvmMember;
if (isEquivalentMethodName(methodSimpleName, operation.getSimpleName())) {
acceptor.accept(genericType);
return;
}
}
}
}

@SuppressWarnings("checkstyle:nestedifdepth")
private static void findCandidateTypes(SARLQuickfixProvider provider, XtendTypeDeclaration sarlContainer,
JvmIdentifiableElement jvmContainer, String methodSimpleName,
IAcceptor<JvmGenericType> acceptor) throws JavaModelException, CoreException {
final JvmType jvmCapacityType = provider.getTypeServices().getTypeReferences().findDeclaredType(Capacity.class, jvmContainer);
if (jvmCapacityType != null) {
final IJavaElement jdtCapacityType = provider.getJavaElementFinder().findElementFor(jvmCapacityType);
if (jdtCapacityType instanceof IType) {
final IType jdtCapacityIType = (IType) jdtCapacityType;
final IJavaSearchScope hierarchyScope = SearchEngine.createStrictHierarchyScope(null, jdtCapacityIType, true, true, null);

final SearchPattern pattern = SearchPattern.createPattern("*",
IJavaSearchConstants.INTERFACE,
IJavaSearchConstants.DECLARATIONS,
SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);

final SearchParticipant[] participants = new SearchParticipant[] {
SearchEngine.getDefaultSearchParticipant(),
};
final SearchEngine engine = new SearchEngine();

final SearchRequestor requestor = new SearchRequestor() {
@Override
public void acceptSearchMatch(SearchMatch match) throws CoreException {
if (match.getAccuracy() == SearchMatch.A_ACCURATE) {
final Object element = match.getElement();
if (element instanceof NamedMember) {
final NamedMember member = (NamedMember) element;
final String fqn = member.getFullyQualifiedName('.', false);
final JvmType type = provider.getTypeServices().getTypeReferences().findDeclaredType(fqn, sarlContainer);
if (type instanceof JvmGenericType) {
final JvmGenericType genericType = (JvmGenericType) type;
findCandidateTypesWithOperation(methodSimpleName, genericType, acceptor);
}
}
}
}
};

engine.search(pattern, participants, hierarchyScope, requestor, new NullProgressMonitor());
}
}
}

/** Create the quick fix if needed.
*
* <p>The user data contains the name of the container type, and the name of the new action.
*
* @param provider the quick fix provider.
* @param issue the issue to fix.
* @param owner the owner of the missed feature.
* @param acceptor the quick fix acceptor.
*/
@SuppressWarnings("checkstyle:nestedifdepth")
public static void accept(SARLQuickfixProvider provider, Issue issue, EObject owner, IssueResolutionAcceptor acceptor) {
if (owner instanceof XAbstractFeatureCall) {
final XAbstractFeatureCall call = (XAbstractFeatureCall) owner;
try {
final String text = call.getConcreteSyntaxFeatureName();
if (!Strings.isEmpty(text)) {
final OutParameter<EObject> container = new OutParameter<>();
if (Utils.getContainerOfType(call, container, null, XtendTypeDeclaration.class)) {
final EObject containerObj = container.get();
if (containerObj instanceof SarlAgent
|| containerObj instanceof SarlBehavior
|| containerObj instanceof SarlSkill) {
final XtendTypeDeclaration typeDeclaration = (XtendTypeDeclaration) containerObj;
final EObject jvmContainer = provider.getJvmAssociations().getPrimaryJvmElement(containerObj);
if (jvmContainer instanceof JvmIdentifiableElement) {
final IAcceptor<JvmGenericType> fqnAcceptor = fqn -> {
final CapacityUseAddModification modification = new CapacityUseAddModification(fqn);
modification.setIssue(issue);
modification.setTools(provider);
acceptor.accept(issue,
MessageFormat.format(Messages.CapacityUseAddModification_0, fqn.getSimpleName()),
MessageFormat.format(Messages.CapacityUseAddModification_1, fqn.getSimpleName()),
JavaPluginImages.IMG_CORRECTION_ADD,
modification,
IProposalRelevance.IMPORT_EXPLICIT);
};
findCandidateTypes(
provider,
typeDeclaration,
(JvmIdentifiableElement) jvmContainer,
text,
fqnAcceptor);
}
}
}
}
} catch (Throwable exception) {
//
}
}
}

@Override
public void apply(EObject element, IModificationContext context) throws Exception {
final XtendTypeDeclaration container = EcoreUtil2.getContainerOfType(element, XtendTypeDeclaration.class);
if (container != null) {
final int insertOffset = getTools().getInsertOffset(container);
final IXtextDocument document = context.getXtextDocument();
final int length = getTools().getSpaceSize(document, insertOffset);
final ReplacingAppendable appendable = getTools().getAppendableFactory().create(document,
(XtextResource) element.eResource(), insertOffset, length);
final boolean changeIndentation = container.getMembers().isEmpty();
if (changeIndentation) {
appendable.increaseIndentation();
}
appendable.newLine();
appendable.append(
getTools().getGrammarAccess().getUsesKeyword());
appendable.append(" "); //$NON-NLS-1$
appendable.append(this.capacity);
if (changeIndentation) {
appendable.decreaseIndentation();
}
appendable.newLine();
appendable.commitChanges();
}
}

}
Expand Up @@ -37,6 +37,8 @@ public class Messages extends NLS {
public static String AddSuppressWarnings_0;
public static String AddSuppressWarnings_1;
public static String AddSuppressWarnings_2;
public static String CapacityUseAddModification_0;
public static String CapacityUseAddModification_1;
public static String ProtectKeywordModification_0;
public static String ProtectKeywordModification_1;
public static String SARLQuickfixProvider_0;
Expand Down
@@ -1,6 +1,8 @@
AddSuppressWarnings_0=the current element
AddSuppressWarnings_1=Add @SuppressWarnings to {0}
AddSuppressWarnings_2=Add the @SuppressWarnings annotation to the element {0}
CapacityUseAddModification_0=Use capacity {0}
CapacityUseAddModification_1=Add the use of the capacity {0}
ProtectKeywordModification_0=Change to ''{0}''
ProtectKeywordModification_1=Change the identifier to ''{0}''.
SARLQuickfixProvider_0=Remove
Expand Down

0 comments on commit 450d578

Please sign in to comment.