/** * Finds all resolutions for issues with a specific issue code. * * @param issueCode * to find resolutions for, may be {@code null} * @param quickfixLabel * to find resolutions for, may be {@code null} * @return {@link List} of resolutions for issues with a specific code */ private List<IssueResolution> resolutionsFor(final String issueCode, final String quickfixLabel) { final List<IssueResolution> resolutions = new ArrayList<IssueResolution>(); for (final Issue issue : issuesWith(issueCode)) { UiThreadDispatcher.dispatchAndWait(new Runnable() { @Override public void run() { if (quickfixLabel == null) { resolutions.addAll(getIssueResolutionProvider().getResolutions(issue)); } else { for (IssueResolution r : getIssueResolutionProvider().getResolutions(issue)) { if (quickfixLabel.equals(r.getLabel())) { resolutions.add(r); } } } } }); } return resolutions; }
/** * Example: {@code // XPECT quickFixList at 'a.<|>method' --> 'import A','do other things' } * * @param expectation * comma separated strings, which are proposed as quick fix * @param resource * injected xtext-file * @param offset * cursor position at '<|>' * @param checkType * 'display': verify list of provided proposals comparing their user-displayed strings. * @param selected * which proposal to pick * @param mode * modus of operation * @param offset2issue * mapping of offset(!) to issues. * @throws Exception * if failing */ @Xpect @ParameterParser(syntax = "('at' (arg2=STRING (arg3=ID (arg4=STRING)? (arg5=ID)? )? )? )?") @ConsumedIssues({ Severity.INFO, Severity.ERROR, Severity.WARNING }) public void quickFixList( @CommaSeparatedValuesExpectation(quoted = true, ordered = true) ICommaSeparatedValuesExpectation expectation, // arg0 @ThisResource XtextResource resource, // arg1 RegionWithCursor offset, // arg2 String checkType, // arg3 String selected, // arg4 String mode, // arg5 @IssuesByLine Multimap<Integer, Issue> offset2issue) throws Exception { List<IssueResolution> resolutions = collectAllResolutions(resource, offset, offset2issue); List<String> resolutionNames = Lists.newArrayList(); for (IssueResolution resolution : resolutions) { resolutionNames.add(resolution.getLabel()); } expectation.assertEquals(resolutionNames); }
/** * CollectAll resolutions under the cursor at offset. * */ List<IssueResolution> collectAllResolutions(XtextResource resource, RegionWithCursor offset, Multimap<Integer, Issue> offset2issue) { EObject script = resource.getContents().get(0); ICompositeNode scriptNode = NodeModelUtils.getNode(script); ILeafNode offsetNode = NodeModelUtils.findLeafNodeAtOffset(scriptNode, offset.getGlobalCursorOffset()); int offStartLine = offsetNode.getTotalStartLine(); List<Issue> allIssues = QuickFixTestHelper.extractAllIssuesInLine(offStartLine, offset2issue); List<IssueResolution> resolutions = Lists.newArrayList(); for (Issue issue : allIssues) { if (issue.getLineNumber() == offsetNode.getStartLine() && issue.getLineNumber() <= offsetNode.getEndLine()) { Display.getDefault().syncExec(() -> resolutions.addAll(quickfixProvider.getResolutions(issue))); } } return resolutions; }
@Override protected IMarkerResolution[] getAdaptedResolutions(List<IssueResolution> resolutions) { // choose valid resolutions final List<IssueResolution> validResolutions = new ArrayList<>(resolutions.size()); if (isMultiApplyAttempt()) { // only those that support multi-apply are valid for (IssueResolution currResolution : resolutions) { if (supportsMultiApply(currResolution)) validResolutions.add(currResolution); } if (validResolutions.size() < resolutions.size()) showError_MultiApplyNotSupported(); } else { // all are valid validResolutions.addAll(resolutions); } // perform wrapping IMarkerResolution[] result = new IMarkerResolution[validResolutions.size()]; for (int i = 0; i < validResolutions.size(); i++) result[i] = new MultiResolutionAdapter(validResolutions.get(i)); return result; }
/** * Assert that application of the target quickfix was successful and the text of the resulting document equals the expected text. * The method ensures that there is one and only one quickfix for the given issue code with the given label. * * @param issueCode * the code of the issue that should have been fixed, may be {@code null} * @param quickfixLabel * the label of the quick fix that should be applied, may be {@code null} * @param expectedContent * the name of the file containing the expected result after applying the quick fix * @param ignoreFormatting * ignore formatting */ private void assertQuickFixExistsAndSuccessful(final String issueCode, final String quickfixLabel, final String expectedContent, final boolean ignoreFormatting) { // Assert amount of quickfixes int resolutionCount = resolutionsFor(issueCode, quickfixLabel).size(); Assert.assertTrue(String.format("There must be exactly one quickfix with label '%s' for issue '%s', but found '%d'.", quickfixLabel, issueCode, resolutionCount), resolutionCount == 1); // Apply quickfix UiThreadDispatcher.dispatchAndWait(new Runnable() { @Override public void run() { List<IssueResolution> resolutions = resolutionsFor(issueCode, quickfixLabel); if (!resolutions.isEmpty()) { resolutions.get(0).apply(); } } }); waitForValidation(); Assert.assertTrue(resolutionsFor(issueCode, quickfixLabel).isEmpty()); String actualContent = getDocument().get(); assertQuickFixProducesExpectedOutput(expectedContent, actualContent, ignoreFormatting); }
private MultiResolutionAdapter(IssueResolution resolution) { if (!(resolution.getModificationContext() instanceof IssueModificationContext)) throw new IllegalArgumentException( "the resolution's modification context must be an IssueModificationContext"); this.issue = ((IssueModificationContext) resolution.getModificationContext()).getIssue(); this.resolution = resolution; }
/** * Returns true iff the given resolution supports being applied to multiple issues / markers at once. */ private boolean supportsMultiApply(IssueResolution resolution) { // must be based on an N4Modification and #supportsMultiApply() returns true return resolution.getModification() instanceof N4ModificationWrapper && ((N4ModificationWrapper) resolution.getModification()).getN4Modification() != null && ((N4ModificationWrapper) resolution.getModification()).getN4Modification().supportsMultiApply(); }
/** * Assert that application of the quick fixes for the given issueCode and label resolve the problem. * * @param issueCode * the code of the issue that should have been fixed, may be {@code null} * @param quickfixLabel * the label of the quickfix, may be {@code null} */ protected void assertQuickFixSuccessful(final String issueCode, final String quickfixLabel) { for (final IssueResolution issueResolution : sortResolutionsByOffsetDecreasing(resolutionsFor(issueCode))) { if (quickfixLabel == null || quickfixLabel.equals(issueResolution.getLabel())) { UiThreadDispatcher.dispatchAndWait(new Runnable() { @Override public void run() { issueResolution.apply(); } }); } } waitForValidation(); Assert.assertTrue(resolutionsFor(issueCode).isEmpty()); }
@Override public List<IssueResolution> getResolutions(Issue issue) { List<IssueResolution> resolutions = new ArrayList<>(super.getResolutions(issue)); Optional<EObject> element = getEObjectToBeFixedFromIssue(issue); if (element.isPresent()) { Collection<IAutomatedIssueResolutionFactory> issueResolutionFactories = findFactories(issue.getCode()); IssueResolutionAcceptor issueResolutionAcceptor = getIssueResolutionAcceptorProvider().get(); issueResolutionFactories.stream().filter(f -> f.resolvePossible(element.get())) .forEach(f -> createIssueResolution(f, issue, element.get(), issueResolutionAcceptor)); resolutions.addAll(issueResolutionAcceptor.getIssueResolutions()); } return resolutions; }
@Override protected List<IssueResolution> getResolutions(Issue issue, List<Method> fixMethods) { List<Method> originalMethods = fixMethods.stream().filter(m -> m.getAnnotation(Fix.class) != null) .collect(Collectors.toList()); List<IssueResolution> resolutions = new ArrayList<>(super.getResolutions(issue, originalMethods)); Optional<EObject> element = getEObjectToBeFixedFromIssue(issue); if (!element.isPresent()) { return resolutions; } List<Method> semanticMethods = fixMethods.stream().filter(m -> m.getAnnotation(SemanticFix.class) != null) .collect(Collectors.toList()); IssueResolutionAcceptor issueResolutionAcceptor = getIssueResolutionAcceptorProvider().get(); for (Method fixMethod : semanticMethods) { try { fixMethod.setAccessible(true); fixMethod.invoke(this, issue, element, issueResolutionAcceptor); } catch (Exception e) { LOGGER.error("Error executing fix method", e); } } List<IssueResolution> semanticResolutions = issueResolutionAcceptor.getIssueResolutions(); resolutions.addAll(semanticResolutions); return resolutions; }
@Override protected ICompletionProposal create(Position posisition, IssueResolution resolution) { if (resolution instanceof TemplateIssueResolution) return createTemplateProposal((TemplateIssueResolution) resolution); else return super.create(posisition, resolution); }
@Override public List<IssueResolution> getIssueResolutions() { List<IssueResolution> result = Lists.newArrayList(super .getIssueResolutions()); result.addAll(resolutions); return result; }
@Override public List<IssueResolution> getResolutions(final Issue issue) { final List<IssueResolution> resolutions = super.getResolutions(issue); resolutions.addAll(from(getDelegates()).transformAndConcat(p -> p.getResolutions(issue)).toList()); return resolutions; }
/** * Invokes quickfix methods and creates IssueResolution objects. Both "native" quickfix providers and Check * quickfix providers are considered. * <p> * {@inheritDoc} */ @Override protected List<IssueResolution> getResolutions(final Issue issue, final List<Method> fixMethods) { final ICoreIssueResolutionAcceptor coreIssueResolutionAcceptor = coreIssueResolutionAcceptorProvider.get(); final IssueResolutionAcceptor defaultIssueResolutionAcceptor = issueResolutionAcceptorProvider.get(); for (Method fixMethod : fixMethods) { try { fixMethod.setAccessible(true); if (Lists.newArrayList(getClass().getMethods()).contains(fixMethod)) { if (fixMethod.getAnnotation(CoreFix.class) != null) { fixMethod.invoke(this, issue, coreIssueResolutionAcceptor); } else { // Legacy code: executes native quickfixes fixMethod.invoke(this, issue, defaultIssueResolutionAcceptor); } } else { // Check quickfixes: collect from Check quickfix providers // TODO optimize the following: it is required to find the provider on which to execute // the fix method for (final ICoreQuickfixProvider p : getProviders()) { if (Iterables.contains(methodsForProvider(p, issue.getCode()), fixMethod)) { fixMethod.invoke(p, issue, coreIssueResolutionAcceptor); } } } // CHECKSTYLE:OFF } catch (Exception e) { // CHECKSTYLE:ON LOGGER.error("Error executing fix method", e); //$NON-NLS-1$ } } final Iterable<IssueResolution> allResolutions = Iterables.concat(Lists.transform(coreIssueResolutionAcceptor.getIssueResolutions(), new Function<CoreIssueResolution, IssueResolution>() { @Override public IssueResolution apply(final CoreIssueResolution from) { return new IssueResolutionWrapper(from); } }), defaultIssueResolutionAcceptor.getIssueResolutions()); return Lists.newArrayList(allResolutions); }
/** * Finds all resolutions for issues with a specific issue code. * * @param issueCode * to find resolutions for, may be {@code null} * @return {@link List} of resolutions for issues with a specific code */ private List<IssueResolution> resolutionsFor(final String issueCode) { return resolutionsFor(issueCode, null); }