diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCodeActions.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCodeActions.java index 18057f086..5f59f84bd 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCodeActions.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCodeActions.java @@ -51,8 +51,8 @@ public List doCodeActions(CodeActionContext context, Range range, DO codeActionParticipant.doCodeAction(diagnostic, range, document, codeActions, sharedSettings, extensionsRegistry); } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error while processing code action participant '" - + codeActionParticipant.getClass().getName() + "'", e); + LOGGER.log(Level.SEVERE, "Error while processing code actions for the participant '" + + codeActionParticipant.getClass().getName() + "'.", e); } } } diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCodeLens.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCodeLens.java index f91734f6f..0619249c3 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCodeLens.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCodeLens.java @@ -14,6 +14,9 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CancellationException; +import java.util.logging.Level; +import java.util.logging.Logger; import org.eclipse.lemminx.dom.DOMDocument; import org.eclipse.lemminx.services.extensions.XMLExtensionsRegistry; @@ -31,6 +34,8 @@ class XMLCodeLens { private final XMLExtensionsRegistry extensionsRegistry; + private static final Logger LOGGER = Logger.getLogger(XMLCodeLens.class.getName()); + public XMLCodeLens(XMLExtensionsRegistry extensionsRegistry) { this.extensionsRegistry = extensionsRegistry; } @@ -39,7 +44,14 @@ public List getCodelens(DOMDocument xmlDocument, XMLCodeLens ICodeLensRequest request = new CodeLensRequest(xmlDocument, settings); List lenses = new ArrayList<>(); for (ICodeLensParticipant participant : extensionsRegistry.getCodeLensParticipants()) { - participant.doCodeLens(request, lenses, cancelChecker); + try { + participant.doCodeLens(request, lenses, cancelChecker); + } catch (CancellationException e) { + throw e; + } catch (Exception e) { + LOGGER.log(Level.SEVERE, + "Error while processing code lens for the participant '" + participant.getClass().getName() + "'.", e); + } } return lenses; } diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCompletions.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCompletions.java index 7a7ea19bb..29f988bd9 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCompletions.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLCompletions.java @@ -277,7 +277,7 @@ public CompletionList doComplete(DOMDocument xmlDocument, Position position, Sha /** * Collect snippets suggestions. - * + * * @param completionRequest completion request. * @param completionResponse completion response. */ @@ -370,7 +370,7 @@ private static Integer getSuffixIndex(String text, String suffix, final int init /** * Returns the limit start offset of the expression according to the current * node. - * + * * @param currentNode the node. * @param offset the offset. * @return the limit start offset of the expression according to the current @@ -436,7 +436,7 @@ private static int getExprStart(String value, int from, int to) { /** * Returns true if completion was triggered inside DTD content (internal or * external DTD) and false otherwise. - * + * * @param node * @param xmlDocument * @return true if completion was triggered inside DTD content (internal or @@ -627,7 +627,7 @@ private void collectOpenTagSuggestions(boolean hasOpenBracket, Range replaceRang try { participant.onTagOpen(completionRequest, completionResponse); } catch (Exception e) { - LOGGER.log(Level.SEVERE, "While performing ICompletionParticipant#onTagOpen", e); + LOGGER.log(Level.SEVERE, "While performing ICompletionParticipant#onTagOpen for participant '" + participant.getClass().getName() + "'.", e); } } DOMElement parentNode = completionRequest.getParentElement(); @@ -763,7 +763,8 @@ private void collectInsideContent(CompletionRequest request, CompletionResponse try { participant.onXMLContent(request, response); } catch (Exception e) { - LOGGER.log(Level.SEVERE, "While performing ICompletionParticipant#onXMLContent", e); + LOGGER.log(Level.SEVERE, "While performing ICompletionParticipant#onXMLContent for participant '" + + participant.getClass().getName() + "'.", e); } } collectionRegionProposals(request, response); @@ -855,7 +856,14 @@ private void collectAttributeNameSuggestions(int nameStart, int nameEnd, Complet boolean generateValue = !isFollowedBy(text, nameEnd, ScannerState.AfterAttributeName, TokenType.DelimiterAssign); for (ICompletionParticipant participant : getCompletionParticipants()) { - participant.onAttributeName(generateValue, completionRequest, completionResponse); + try { + participant.onAttributeName(generateValue, completionRequest, completionResponse); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, + "While performing ICompletionParticipant#onAttributeName for participant '" + + participant.getClass().getName() + "'.", + e); + } } } catch (BadLocationException e) { LOGGER.log(Level.SEVERE, "While performing Completions, getReplaceRange() was given a bad Offset location", @@ -899,7 +907,14 @@ private void collectAttributeValueSuggestions(int valueStart, int valueEnd, Comp completionRequest.setReplaceRange(replaceRange); completionRequest.setAddQuotes(addQuotes); for (ICompletionParticipant participant : completionParticipants) { - participant.onAttributeValue(valuePrefix, completionRequest, completionResponse); + try { + participant.onAttributeValue(valuePrefix, completionRequest, completionResponse); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, + "While performing ICompletionParticipant#onAttributeValue for participant '" + + participant.getClass().getName() + "'.", + e); + } } } catch (BadLocationException e) { LOGGER.log(Level.SEVERE, @@ -912,7 +927,7 @@ private void collectAttributeValueSuggestions(int valueStart, int valueEnd, Comp /** * Collect completion items for DTD systemId - * + * * @param valueStart the start offset of the systemId value, including * quote * @param valueEnd the end offset of the systemId value, including @@ -936,7 +951,14 @@ private void collectDTDSystemIdSuggestions(int valueStart, int valueEnd, Complet Range replaceRange = getReplaceRange(valueContentStart, valueContentEnd, completionRequest); completionRequest.setReplaceRange(replaceRange); for (ICompletionParticipant participant : completionParticipants) { - participant.onDTDSystemId(valuePrefix, completionRequest, completionResponse); + try { + participant.onDTDSystemId(valuePrefix, completionRequest, completionResponse); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, + "While performing ICompletionParticipant#onDTDSystemId for participant '" + + participant.getClass().getName() + "'.", + e); + } } } catch (BadLocationException e) { LOGGER.log(Level.SEVERE, @@ -959,7 +981,7 @@ private static int scanNextForEndPos(int offset, Scanner scanner, TokenType next /** * Returns list of {@link ICompletionParticipant}. - * + * * @return list of {@link ICompletionParticipant}. */ private Collection getCompletionParticipants() { @@ -973,7 +995,7 @@ private static boolean isFollowedBy(String s, int offset, ScannerState intialSta /** * Returns starting offset of 'expectedToken' if it the next non whitespace * token after 'initialState' - * + * * @param s * @param offset * @param intialState diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLDefinition.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLDefinition.java index 254e85766..8f5e2a583 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLDefinition.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLDefinition.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.CancellationException; import java.util.logging.Level; import java.util.logging.Logger; @@ -57,7 +58,14 @@ public List findDefinition(DOMDocument document, Positio // Custom definition List locations = new ArrayList<>(); for (IDefinitionParticipant participant : extensionsRegistry.getDefinitionParticipants()) { - participant.findDefinition(request, locations, cancelChecker); + try { + participant.findDefinition(request, locations, cancelChecker); + } catch (CancellationException e) { + throw e; + } catch (Exception e) { + LOGGER.log(Level.SEVERE, + "Error while processing definitions for the participant '" + participant.getClass().getName() + "'.", e); + } } // Start end tag definition findStartEndTagDefinition(request, locations); @@ -66,7 +74,7 @@ public List findDefinition(DOMDocument document, Positio /** * Find start end tag definition. - * + * * @param request the definition request * @param locations the locations */ diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLDiagnostics.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLDiagnostics.java index 3b054d509..1be4daf50 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLDiagnostics.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLDiagnostics.java @@ -14,11 +14,15 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CancellationException; +import java.util.logging.Level; +import java.util.logging.Logger; import org.eclipse.lemminx.dom.DOMDocument; import org.eclipse.lemminx.extensions.contentmodel.settings.XMLValidationSettings; import org.eclipse.lemminx.services.extensions.XMLExtensionsRegistry; import org.eclipse.lemminx.services.extensions.diagnostics.IDiagnosticsParticipant; +import org.eclipse.lemminx.uriresolver.CacheResourceDownloadingException; import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.jsonrpc.CancelChecker; @@ -29,6 +33,7 @@ class XMLDiagnostics { private final XMLExtensionsRegistry extensionsRegistry; + private static final Logger LOGGER = Logger.getLogger(XMLDiagnostics.class.getName()); public XMLDiagnostics(XMLExtensionsRegistry extensionsRegistry) { this.extensionsRegistry = extensionsRegistry; @@ -45,7 +50,7 @@ public List doDiagnostics(DOMDocument xmlDocument, XMLValidationSett /** * Do validation with extension (XML Schema, etc) - * + * * @param xmlDocument * @param diagnostics * @param validationSettings @@ -55,7 +60,14 @@ private void doExtensionsDiagnostics(DOMDocument xmlDocument, List d XMLValidationSettings validationSettings, CancelChecker monitor) { for (IDiagnosticsParticipant diagnosticsParticipant : extensionsRegistry.getDiagnosticsParticipants()) { monitor.checkCanceled(); - diagnosticsParticipant.doDiagnostics(xmlDocument, diagnostics, validationSettings, monitor); + try { + diagnosticsParticipant.doDiagnostics(xmlDocument, diagnostics, validationSettings, monitor); + } catch (CancellationException | CacheResourceDownloadingException e) { + throw e; + } catch (Exception e) { + LOGGER.log(Level.SEVERE, + "Error while processing diagnostics for the participant '" + diagnosticsParticipant.getClass().getName() + "'.", e); + } } } diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLDocumentLink.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLDocumentLink.java index 37781d361..c6de8a491 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLDocumentLink.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLDocumentLink.java @@ -14,6 +14,9 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CancellationException; +import java.util.logging.Level; +import java.util.logging.Logger; import org.eclipse.lemminx.dom.DOMDocument; import org.eclipse.lemminx.services.extensions.IDocumentLinkParticipant; @@ -28,6 +31,8 @@ class XMLDocumentLink { private final XMLExtensionsRegistry extensionsRegistry; + private static Logger LOGGER = Logger.getLogger(XMLDocumentLink.class.getName()); + public XMLDocumentLink(XMLExtensionsRegistry extensionsRegistry) { this.extensionsRegistry = extensionsRegistry; } @@ -35,30 +40,15 @@ public XMLDocumentLink(XMLExtensionsRegistry extensionsRegistry) { public List findDocumentLinks(DOMDocument document) { List newLinks = new ArrayList<>(); for (IDocumentLinkParticipant participant : extensionsRegistry.getDocumentLinkParticipants()) { - participant.findDocumentLinks(document, newLinks); + try { + participant.findDocumentLinks(document, newLinks); + } catch (CancellationException e) { + throw e; + } catch (Exception e) { + LOGGER.log(Level.SEVERE, + "Error while processing document links for the participant '" + participant.getClass().getName() + "'.", e); + } } - // TODO: call extension - /* - * let rootAbsoluteUrl: Uri | null = null; - * - * Scanner scanner = XMLScanner.createScanner(document.getText(), 0); TokenType - * token = scanner.scan(); let afterHrefOrSrc = false; let afterBase = false; - * let base: string | undefined = void 0; while (token != TokenType.EOS) { - * switch (token) { case TokenType.StartTag: if (!base) { let tagName = - * scanner.getTokenText().toLowerCase(); afterBase = tagName === 'base'; } - * break; case TokenType.AttributeName: let attributeName = - * scanner.getTokenText().toLowerCase(); afterHrefOrSrc = attributeName === - * 'src' || attributeName === 'href'; break; case TokenType.AttributeValue: if - * (afterHrefOrSrc) { let attributeValue = scanner.getTokenText(); if - * (!afterBase) { // don't highlight the base link itself let link = - * createLink(document, documentContext, attributeValue, - * scanner.getTokenOffset(), scanner.getTokenEnd(), base); if (link) { - * newLinks.push(link); } } if (afterBase && typeof base === 'undefined') { base - * = normalizeRef(attributeValue, document.languageId); if (base && - * documentContext) { base = documentContext.resolveReference(base, - * document.uri); } } afterBase = false; afterHrefOrSrc = false; } break; } - * token = scanner.scan(); } - */ return newLinks; } } diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLHighlighting.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLHighlighting.java index 96348c843..2b01be689 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLHighlighting.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLHighlighting.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.CancellationException; import java.util.logging.Level; import java.util.logging.Logger; @@ -122,7 +123,14 @@ private void fillWithCustomHighlights(DOMNode node, Position position, int offse List highlights, CancelChecker cancelChecker) { // Consume highlighting participant for (IHighlightingParticipant highlightingParticipant : extensionsRegistry.getHighlightingParticipants()) { - highlightingParticipant.findDocumentHighlights(node, position, offset, highlights, cancelChecker); + try { + highlightingParticipant.findDocumentHighlights(node, position, offset, highlights, cancelChecker); + } catch (CancellationException e) { + throw e; + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error while processing highlights for the participant '" + + highlightingParticipant.getClass().getName() + "'.", e); + } } } } diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLReference.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLReference.java index 3c58c707a..cb2e27a29 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLReference.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLReference.java @@ -14,6 +14,9 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CancellationException; +import java.util.logging.Level; +import java.util.logging.Logger; import org.eclipse.lemminx.dom.DOMDocument; import org.eclipse.lemminx.services.extensions.IReferenceParticipant; @@ -31,6 +34,8 @@ class XMLReference { private final XMLExtensionsRegistry extensionsRegistry; + private static Logger LOGGER = Logger.getLogger(XMLReference.class.getName()); + public XMLReference(XMLExtensionsRegistry extensionsRegistry) { this.extensionsRegistry = extensionsRegistry; } @@ -39,7 +44,14 @@ public List findReferences(DOMDocument document, Position po CancelChecker cancelChecker) { List locations = new ArrayList<>(); for (IReferenceParticipant participant : extensionsRegistry.getReferenceParticipants()) { - participant.findReference(document, position, context, locations, cancelChecker); + try { + participant.findReference(document, position, context, locations, cancelChecker); + } catch (CancellationException e) { + throw e; + } catch (Exception e) { + LOGGER.log(Level.SEVERE, + "Error while processing references for the participant '" + participant.getClass().getName() + "'.", e); + } } return locations; } diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLRename.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLRename.java index 3ac8af904..ddfe0b8c2 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLRename.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLRename.java @@ -41,7 +41,7 @@ /** * Handle all rename requests - * + * * Author: Nikolas Komonen - nkomonen@redhat.com */ public class XMLRename { @@ -76,7 +76,12 @@ public WorkspaceEdit doRename(DOMDocument xmlDocument, Position position, String List textEdits = new ArrayList<>(); for (IRenameParticipant participant : extensionsRegistry.getRenameParticipants()) { - participant.doRename(renameRequest, textEdits); + try { + participant.doRename(renameRequest, textEdits); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error while processing rename for the participant '" + + participant.getClass().getName() + "'.", e); + } } for (TextEdit textEdit : getRenameTextEdits(xmlDocument, node, position, newText)) { @@ -111,7 +116,7 @@ private List getRenameTextEdits(DOMDocument xmlDocument, DOMNode node, /** * Returns DOMElement associated with node - * + * * @param node node representing an element or attribute * @return associated DOMElement */ @@ -252,7 +257,7 @@ private WorkspaceEdit createWorkspaceEdit(String documentURI, List tex /** * Creates a list of start and end tag rename's. - * + * * @param startTagRange * @param endTagRange * @param newText @@ -272,7 +277,7 @@ private static List getRenameList(Range startTagRange, Range endTagRan /** * Renames all occurences of the namespace in a document, that match the given * old namespace. - * + * * @param document * @param oldNamespace * @param newNamespace @@ -308,7 +313,7 @@ private static List renameAllNamespaceOccurrences(DOMDocument document /** * Will traverse through the given elements and their children, updating all * namespaces that match the given old namespace. - * + * * @param document * @param edits * @param elements @@ -359,7 +364,7 @@ private static List renameElementNamespace(DOMDocument document, DOMEl /** * Will rename the namespace of an element's attribute values with the matching * namespace. - * + * * @param document * @param element * @param oldNamespace @@ -396,7 +401,7 @@ private static List renameElementAttributeValueNamespace(DOMDocument d /** * Returns the ranges of the namespace of a start and end tag of an element. - * + * * @param document * @param element * @param namespaceLength diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLSymbolsProvider.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLSymbolsProvider.java index bc32a650c..5479f474c 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLSymbolsProvider.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLSymbolsProvider.java @@ -16,6 +16,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.concurrent.CancellationException; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import java.util.logging.Logger; @@ -362,29 +363,51 @@ private boolean processSymbolsParticipants(DOMDocument xmlDocument, SymbolInform // Process replace symbol providers participants Collection replaceParticipants = resultParticipant.getReplaceParticipants(); if (!replaceParticipants.isEmpty()) { + boolean successfulReplace = false; if (replaceParticipants.size() > 1) { LOGGER.log(Level.WARNING, "There are '" + replaceParticipants.size() + "' replace participants"); } for (ISymbolsProviderParticipant replaceParticipant : replaceParticipants) { - if (symbolInformations != null) { - replaceParticipant.findSymbolInformations(xmlDocument, symbolInformations, filter, cancelChecker); - } - if (documentSymbols != null) { - replaceParticipant.findDocumentSymbols(xmlDocument, documentSymbols, filter, cancelChecker); + try { + if (symbolInformations != null) { + replaceParticipant.findSymbolInformations(xmlDocument, symbolInformations, filter, cancelChecker); + } + if (documentSymbols != null) { + replaceParticipant.findDocumentSymbols(xmlDocument, documentSymbols, filter, cancelChecker); + } + successfulReplace = true; + } catch (CancellationException e) { + throw e; + } catch (Exception e) { + LOGGER.log(Level.SEVERE, + "Error while processing symbols for '" + replaceParticipant.getClass().getName() + "'.", e); } } - return true; + // If at least 1 replace participant didn't crash, use the replace result; + // otherwise just use the default + if (successfulReplace) { + return true; + } } // Process insert symbol providers participants Collection insertParticipants = resultParticipant.getInsertParticipants(); if (!insertParticipants.isEmpty()) { for (ISymbolsProviderParticipant insertParticipant : insertParticipants) { - if (symbolInformations != null) { - insertParticipant.findSymbolInformations(xmlDocument, symbolInformations, filter, cancelChecker); - } - if (documentSymbols != null) { - insertParticipant.findDocumentSymbols(xmlDocument, documentSymbols, filter, cancelChecker); + try { + if (symbolInformations != null) { + insertParticipant.findSymbolInformations(xmlDocument, symbolInformations, filter, cancelChecker); + } + if (documentSymbols != null) { + insertParticipant.findDocumentSymbols(xmlDocument, documentSymbols, filter, cancelChecker); + } + } catch (CancellationException e) { + throw e; + } catch (Exception e) { + LOGGER.log(Level.SEVERE, + "Error while processing symbols for the participant '" + + insertParticipant.getClass().getName() + "'.", + e); } } } diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLTypeDefinition.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLTypeDefinition.java index 0824df5c0..6f1b8766a 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLTypeDefinition.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/XMLTypeDefinition.java @@ -14,6 +14,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.CancellationException; import java.util.logging.Level; import java.util.logging.Logger; @@ -51,7 +52,14 @@ public List findTypeDefinition(DOMDocument document, Pos } List locations = new ArrayList<>(); for (ITypeDefinitionParticipant participant : extensionsRegistry.getTypeDefinitionParticipants()) { - participant.findTypeDefinition(request, locations, cancelChecker); + try { + participant.findTypeDefinition(request, locations, cancelChecker); + } catch (CancellationException e) { + throw e; + } catch (Exception e) { + LOGGER.log(Level.SEVERE, + "Error while processing type definitions for the participant '" + participant.getClass().getName() + "'.", e); + } } return locations; } diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/utils/XMLBuilder.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/utils/XMLBuilder.java index 1f8ef1d1d..265cb2c20 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/utils/XMLBuilder.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/utils/XMLBuilder.java @@ -15,6 +15,8 @@ import static org.eclipse.lemminx.utils.StringUtils.normalizeSpace; import java.util.Collection; +import java.util.logging.Level; +import java.util.logging.Logger; import org.eclipse.lemminx.dom.DOMAttr; import org.eclipse.lemminx.dom.DOMComment; @@ -37,6 +39,8 @@ public class XMLBuilder { private final Collection formatterParticipants; + private static final Logger LOGGER = Logger.getLogger(XMLBuilder.class.getName()); + public XMLBuilder(SharedSettings sharedSettings, String whitespacesIndent, String lineDelimiter) { this(sharedSettings, whitespacesIndent, lineDelimiter, null); } @@ -126,9 +130,9 @@ public XMLBuilder addSingleAttribute(String name, String value, boolean surround /** * Used when only one attribute is being added to a node. - * + * * It will not perform any linefeeds and only basic indentation. - * + * * @param name attribute name * @param value attribute value * @param surroundWithQuotes true if quotes should be added around originalValue @@ -145,9 +149,9 @@ private XMLBuilder addSingleAttribute(String name, String value, boolean surroun /** * Add prolog attribute - * + * * It will not perform any linefeeds and only basic indentation. - * + * * @param attr attribute * @return this XML Builder */ @@ -159,9 +163,9 @@ public XMLBuilder addPrologAttribute(DOMAttr attr) { /** * Used when you are knowingly adding multiple attributes. - * + * * Does linefeeds and indentation. - * + * * @param name * @param value * @param level @@ -197,10 +201,10 @@ private XMLBuilder addAttribute(DOMAttr attr, int level, boolean surroundWithQuo /** * Builds the attribute {name, '=', and value}. - * + * * Never puts quotes around unquoted values unless indicated to by * 'surroundWithQuotes' - * + * * @param name name of the attribute * @param equalsSign true if equals sign exists, false otherwise * @param originalValue value of the attribute @@ -237,8 +241,13 @@ private void addAttributeContents(String name, boolean equalsSign, String origin private void formatAttributeValue(String name, String valueWithoutQuote, Character quote, DOMAttr attr) { if (formatterParticipants != null) { for (IFormatterParticipant formatterParticipant : formatterParticipants) { - if (formatterParticipant.formatAttributeValue(name, valueWithoutQuote, quote, attr, this)) { - return; + try { + if (formatterParticipant.formatAttributeValue(name, valueWithoutQuote, quote, attr, this)) { + return; + } + } catch (Exception e) { + LOGGER.log(Level.SEVERE, + "Error while processing format attributes for the participant '" + formatterParticipant.getClass().getName() + "'.", e); } } } @@ -269,7 +278,7 @@ public XMLBuilder linefeed() { /** * Returns this XMLBuilder with text added - * + * * @param text the text to add * @return this XMLBuilder with text added */ @@ -281,7 +290,7 @@ public XMLBuilder addContent(String text) { * Returns this XMLBuilder with text added depending on * isWhitespaceContent, hasSiblings and * delimiter - * + * * @param text the proposed text to add * @param isWhitespaceContent whether or not the text contains only whitespace * content diff --git a/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/XMLAssert.java b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/XMLAssert.java index 31943237f..0345e66e9 100644 --- a/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/XMLAssert.java +++ b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/XMLAssert.java @@ -19,6 +19,8 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.net.URI; +import java.net.URISyntaxException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -527,7 +529,11 @@ public static void testCodeActionsFor(String xml, Diagnostic diagnostic, String public static void testCodeActionsFor(String xml, Diagnostic diagnostic, String catalogPath, SharedSettings sharedSettings, CodeAction... expected) throws BadLocationException { + testCodeActionsFor(xml, diagnostic, catalogPath, sharedSettings, null, expected); + } + public static void testCodeActionsFor(String xml, Diagnostic diagnostic, String catalogPath, + SharedSettings sharedSettings, XMLLanguageService xmlLanguageService, CodeAction... expected) throws BadLocationException { int offset = xml.indexOf('|'); Range range = null; @@ -543,7 +549,9 @@ public static void testCodeActionsFor(String xml, Diagnostic diagnostic, String range = diagnostic.getRange(); } - XMLLanguageService xmlLanguageService = new XMLLanguageService(); + if (xmlLanguageService == null) { + xmlLanguageService = new XMLLanguageService(); + } ContentModelSettings cmSettings = new ContentModelSettings(); cmSettings.setUseCache(false); @@ -708,9 +716,15 @@ public static void testDocumentLinkFor(String xml, String fileURI, DocumentLink. } public static void testDocumentLinkFor(String xml, String fileURI, String catalogPath, DocumentLink... expected) { + testDocumentLinkFor(null, xml, fileURI, catalogPath, expected); + } + + public static void testDocumentLinkFor(XMLLanguageService xmlLanguageService, String xml, String fileURI, String catalogPath, DocumentLink... expected) { TextDocument document = new TextDocument(xml, fileURI != null ? fileURI : "test.xml"); - XMLLanguageService xmlLanguageService = new XMLLanguageService(); + if (xmlLanguageService == null) { + xmlLanguageService = new XMLLanguageService(); + } ContentModelSettings settings = new ContentModelSettings(); settings.setUseCache(false); @@ -866,13 +880,20 @@ public static void testDefinitionFor(String xml, LocationLink... expected) throw public static void testDefinitionFor(String value, String fileURI, LocationLink... expected) throws BadLocationException { + testDefinitionFor(null, value, fileURI, expected); + } + + public static void testDefinitionFor(XMLLanguageService xmlLanguageService, String value, String fileURI, LocationLink... expected) + throws BadLocationException { int offset = value.indexOf('|'); value = value.substring(0, offset) + value.substring(offset + 1); TextDocument document = new TextDocument(value, fileURI != null ? fileURI : "test://test/test.xml"); Position position = document.positionAt(offset); - XMLLanguageService xmlLanguageService = new XMLLanguageService(); + if (xmlLanguageService == null) { + xmlLanguageService = new XMLLanguageService(); + } ContentModelSettings settings = new ContentModelSettings(); settings.setUseCache(false); @@ -953,13 +974,20 @@ public static void testReferencesFor(String xml, Location... expected) throws Ba public static void testReferencesFor(String value, String fileURI, Location... expected) throws BadLocationException { + testReferencesFor(null, value, fileURI, expected); + } + + public static void testReferencesFor(XMLLanguageService xmlLanguageService, String value, String fileURI, Location... expected) + throws BadLocationException { int offset = value.indexOf('|'); value = value.substring(0, offset) + value.substring(offset + 1); TextDocument document = new TextDocument(value, fileURI != null ? fileURI : "test://test/test.xml"); Position position = document.positionAt(offset); - XMLLanguageService xmlLanguageService = new XMLLanguageService(); + if (xmlLanguageService == null) { + xmlLanguageService = new XMLLanguageService(); + } ContentModelSettings settings = new ContentModelSettings(); settings.setUseCache(false); @@ -992,10 +1020,15 @@ public static void testCodeLensFor(String xml, CodeLens... expected) throws BadL } public static void testCodeLensFor(String value, String fileURI, CodeLens... expected) throws BadLocationException { + testCodeLensFor(value, fileURI, new XMLLanguageService(), expected); + } + public static void testCodeLensFor(String value, String fileURI, XMLLanguageService xmlLanguageService, CodeLens... expected) { TextDocument document = new TextDocument(value, fileURI != null ? fileURI : "test://test/test.xml"); - XMLLanguageService xmlLanguageService = new XMLLanguageService(); + if (xmlLanguageService == null) { + xmlLanguageService = new XMLLanguageService(); + } ContentModelSettings settings = new ContentModelSettings(); settings.setUseCache(false); @@ -1012,7 +1045,6 @@ public static void testCodeLensFor(String value, String fileURI, CodeLens... exp List actual = xmlLanguageService.getCodeLens(xmlDocument, codeLensSettings, () -> { }); assertCodeLens(actual, expected); - } public static CodeLens cl(Range range, String title, String command) { @@ -1077,7 +1109,12 @@ public static DocumentHighlight hl(Range range, DocumentHighlightKind kind) { return new DocumentHighlight(range, kind); } - public static void assertHighlights(String value, int[] expectedMatches, String elementName) + public static void assertHighlights(String value, int[] expectedMatches, String elementName) throws BadLocationException { + assertHighlights(null, value, expectedMatches, elementName); + } + + public static void assertHighlights(XMLLanguageService languageService, String value, int[] expectedMatches, + String elementName) throws BadLocationException { int offset = value.indexOf("|"); value = value.substring(0, offset) + value.substring(offset + 1); @@ -1086,7 +1123,9 @@ public static void assertHighlights(String value, int[] expectedMatches, String Position position = document.positionAt(offset); - XMLLanguageService languageService = new XMLLanguageService(); + if (languageService == null) { + languageService = new XMLLanguageService(); + } List highlights = languageService.findDocumentHighlights(document, position); assertEquals(expectedMatches.length, highlights.size()); for (int i = 0; i < highlights.size(); i++) { @@ -1117,6 +1156,11 @@ public static void assertFormat(String unformatted, String expected, SharedSetti public static void assertFormat(String unformatted, String expected, SharedSettings sharedSettings, String uri, Boolean considerRangeFormat) throws BadLocationException { + assertFormat(null, unformatted, expected, sharedSettings, uri, considerRangeFormat); + } + + public static void assertFormat(XMLLanguageService languageService, String unformatted, String expected, SharedSettings sharedSettings, String uri, + Boolean considerRangeFormat) throws BadLocationException { Range range = null; int rangeStart = considerRangeFormat ? unformatted.indexOf('|') : -1; int rangeEnd = considerRangeFormat ? unformatted.lastIndexOf('|') : -1; @@ -1131,7 +1175,9 @@ public static void assertFormat(String unformatted, String expected, SharedSetti } TextDocument document = new TextDocument(unformatted, uri); - XMLLanguageService languageService = new XMLLanguageService(); + if (languageService == null) { + languageService = new XMLLanguageService(); + } List edits = languageService.format(document, range, sharedSettings); String formatted = edits.stream().map(edit -> edit.getNewText()).collect(Collectors.joining("")); @@ -1156,6 +1202,11 @@ public static void assertRename(String value, String newText) throws BadLocation public static void assertRename(String value, String newText, List expectedEdits) throws BadLocationException { + assertRename(null, value, newText, expectedEdits); + } + + public static void assertRename(XMLLanguageService languageService, String value, String newText, List expectedEdits) + throws BadLocationException { int offset = value.indexOf("|"); value = value.substring(0, offset) + value.substring(offset + 1); @@ -1163,7 +1214,9 @@ public static void assertRename(String value, String newText, List exp Position position = document.positionAt(offset); - XMLLanguageService languageService = new XMLLanguageService(); + if (languageService == null) { + languageService = new XMLLanguageService(); + } WorkspaceEdit workspaceEdit = languageService.doRename(document, position, newText); List actualEdits = workspaceEdit.getChanges().get("test://test/test.html"); assertArrayEquals(expectedEdits.toArray(), actualEdits.toArray()); diff --git a/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/services/extensions/ErrorParticipantLanguageServiceTest.java b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/services/extensions/ErrorParticipantLanguageServiceTest.java new file mode 100644 index 000000000..9c446fe88 --- /dev/null +++ b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/services/extensions/ErrorParticipantLanguageServiceTest.java @@ -0,0 +1,534 @@ +/******************************************************************************* +* Copyright (c) 2020 Red Hat Inc. and others. +* All rights reserved. This program and the accompanying materials +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v20.html +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package org.eclipse.lemminx.services.extensions; + +import static org.eclipse.lemminx.XMLAssert.assertFormat; +import static org.eclipse.lemminx.XMLAssert.assertHighlights; +import static org.eclipse.lemminx.XMLAssert.assertHover; +import static org.eclipse.lemminx.XMLAssert.assertRename; +import static org.eclipse.lemminx.XMLAssert.c; +import static org.eclipse.lemminx.XMLAssert.ca; +import static org.eclipse.lemminx.XMLAssert.cl; +import static org.eclipse.lemminx.XMLAssert.d; +import static org.eclipse.lemminx.XMLAssert.dl; +import static org.eclipse.lemminx.XMLAssert.ds; +import static org.eclipse.lemminx.XMLAssert.hl; +import static org.eclipse.lemminx.XMLAssert.ll; +import static org.eclipse.lemminx.XMLAssert.r; +import static org.eclipse.lemminx.XMLAssert.si; +import static org.eclipse.lemminx.XMLAssert.te; +import static org.eclipse.lemminx.XMLAssert.testCodeActionsFor; +import static org.eclipse.lemminx.XMLAssert.testCodeLensFor; +import static org.eclipse.lemminx.XMLAssert.testCompletionFor; +import static org.eclipse.lemminx.XMLAssert.testDefinitionFor; +import static org.eclipse.lemminx.XMLAssert.testDiagnosticsFor; +import static org.eclipse.lemminx.XMLAssert.testDocumentLinkFor; +import static org.eclipse.lemminx.XMLAssert.testDocumentSymbolsFor; +import static org.eclipse.lemminx.XMLAssert.testReferencesFor; +import static org.eclipse.lemminx.XMLAssert.testSymbolInformationsFor; +import static org.eclipse.lemminx.XMLAssert.testTypeDefinitionFor; + +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.eclipse.lemminx.commons.BadLocationException; +import org.eclipse.lemminx.dom.DOMAttr; +import org.eclipse.lemminx.dom.DOMDocument; +import org.eclipse.lemminx.dom.DOMNode; +import org.eclipse.lemminx.extensions.contentmodel.participants.XMLSyntaxErrorCode; +import org.eclipse.lemminx.extensions.contentmodel.settings.ContentModelSettings; +import org.eclipse.lemminx.extensions.contentmodel.settings.XMLValidationSettings; +import org.eclipse.lemminx.services.DocumentSymbolsResult; +import org.eclipse.lemminx.services.SymbolInformationResult; +import org.eclipse.lemminx.services.XMLLanguageService; +import org.eclipse.lemminx.services.extensions.codelens.ICodeLensParticipant; +import org.eclipse.lemminx.services.extensions.codelens.ICodeLensRequest; +import org.eclipse.lemminx.services.extensions.diagnostics.IDiagnosticsParticipant; +import org.eclipse.lemminx.services.extensions.format.IFormatterParticipant; +import org.eclipse.lemminx.settings.SharedSettings; +import org.eclipse.lemminx.settings.XMLSymbolFilter; +import org.eclipse.lemminx.settings.XMLSymbolSettings; +import org.eclipse.lemminx.utils.XMLBuilder; +import org.eclipse.lsp4j.CodeAction; +import org.eclipse.lsp4j.CodeLens; +import org.eclipse.lsp4j.CompletionItem; +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DiagnosticSeverity; +import org.eclipse.lsp4j.DocumentHighlight; +import org.eclipse.lsp4j.DocumentLink; +import org.eclipse.lsp4j.DocumentSymbol; +import org.eclipse.lsp4j.Hover; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.LocationLink; +import org.eclipse.lsp4j.MarkupContent; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.ReferenceContext; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.SymbolKind; +import org.eclipse.lsp4j.TextEdit; +import org.eclipse.lsp4j.jsonrpc.CancelChecker; +import org.junit.jupiter.api.Test; + +/** + * Tests to ensure that if a participant throws an exception, the language + * server still functions + * + * @author datho7561 + */ +public class ErrorParticipantLanguageServiceTest { + + /** + * Adds participants that throw runtime exceptions, as well as simple + * participants that always return the same result. Does not include all the + * default participants. + */ + static class ErrorParticipantLanguageService extends XMLLanguageService { + + public static final CodeLens TEST_CODE_LENS = cl(r(0, 0, 0, 0), "a", "a"); + public static final LocationLink TEST_LOCATION_LINK = ll("src/hello", r(0, 0, 0, 2), r(0, 0, 0, 1)); + public static final Diagnostic TEST_DIAGNOSTIC = d(0, 0, 0, XMLSyntaxErrorCode.ElementUnterminated); + public static final DocumentLink TEST_DOCLINK = dl(r(0, 0, 0, 0), "src/hello"); + public static final DocumentHighlight TEST_HIGHLIGHT = hl(r(0, 2, 0, 3)); + public static final Hover TEST_HOVER = new Hover(new MarkupContent("markdown", "contents"), r(0, 0, 0, 2)); + public static final Location TEST_LOCATION = new Location("src/hello", r(0, 0, 0, 1)); + private static final SymbolInformation TEST_SI = si("hello", SymbolKind.Array, TEST_LOCATION, "hi"); + protected static final CompletionItem TEST_COMPLETION_ITEM = c("aaa", "bbb"); + protected static final DocumentSymbol TEST_DS = ds("hello", SymbolKind.Array, r(0, 0, 0, 1), r(0, 0, 0, 1), + "detail", Collections.emptyList()); + + public ErrorParticipantLanguageService() { + super(); + + this.registerCodeActionParticipant(new ICodeActionParticipant() { + @Override + public void doCodeAction(Diagnostic diagnostic, Range range, DOMDocument document, + List codeActions, SharedSettings sharedSettings, + IComponentProvider componentProvider) { + throw new RuntimeException("This participant is broken"); + } + }); + this.registerCodeActionParticipant(new ICodeActionParticipant() { + @Override + public void doCodeAction(Diagnostic diagnostic, Range range, DOMDocument document, + List codeActions, SharedSettings sharedSettings, + IComponentProvider componentProvider) { + codeActions.add(ca(diagnostic, te(0, 0, 0, 0, "a"))); + } + }); + + this.registerCodeLensParticipant(new ICodeLensParticipant() { + @Override + public void doCodeLens(ICodeLensRequest request, List lenses, CancelChecker cancelChecker) { + throw new RuntimeException("This participant is broken"); + } + }); + this.registerCodeLensParticipant(new ICodeLensParticipant() { + @Override + public void doCodeLens(ICodeLensRequest request, List lenses, CancelChecker cancelChecker) { + lenses.add(TEST_CODE_LENS); + } + }); + + this.registerCompletionParticipant(new ICompletionParticipant() { + + @Override + public void onTagOpen(ICompletionRequest completionRequest, ICompletionResponse completionResponse) + throws Exception { + throw new RuntimeException("This participant is broken"); + } + + @Override + public void onXMLContent(ICompletionRequest request, ICompletionResponse response) throws Exception { + throw new RuntimeException("This participant is broken"); + } + + @Override + public void onAttributeName(boolean generateValue, ICompletionRequest request, + ICompletionResponse response) throws Exception { + throw new RuntimeException("This participant is broken"); + } + + @Override + public void onAttributeValue(String valuePrefix, ICompletionRequest request, + ICompletionResponse response) throws Exception { + throw new RuntimeException("This participant is broken"); + } + + @Override + public void onDTDSystemId(String valuePrefix, ICompletionRequest request, ICompletionResponse response) + throws Exception { + throw new RuntimeException("This participant is broken"); + } + + }); + this.registerCompletionParticipant(new ICompletionParticipant() { + + @Override + public void onTagOpen(ICompletionRequest completionRequest, ICompletionResponse completionResponse) + throws Exception { + completionResponse.addCompletionAttribute(TEST_COMPLETION_ITEM); + } + + @Override + public void onXMLContent(ICompletionRequest request, ICompletionResponse response) throws Exception { + response.addCompletionAttribute(TEST_COMPLETION_ITEM); + } + + @Override + public void onAttributeName(boolean generateValue, ICompletionRequest request, + ICompletionResponse response) throws Exception { + response.addCompletionAttribute(TEST_COMPLETION_ITEM); + } + + @Override + public void onAttributeValue(String valuePrefix, ICompletionRequest request, + ICompletionResponse response) throws Exception { + response.addCompletionAttribute(TEST_COMPLETION_ITEM); + } + + @Override + public void onDTDSystemId(String valuePrefix, ICompletionRequest request, ICompletionResponse response) + throws Exception { + response.addCompletionAttribute(TEST_COMPLETION_ITEM); + } + + }); + + this.registerDefinitionParticipant(new IDefinitionParticipant() { + @Override + public void findDefinition(IDefinitionRequest request, List locations, + CancelChecker cancelChecker) { + throw new RuntimeException("This participant is broken"); + } + }); + this.registerDefinitionParticipant(new IDefinitionParticipant() { + @Override + public void findDefinition(IDefinitionRequest request, List locations, + CancelChecker cancelChecker) { + locations.add(TEST_LOCATION_LINK); + } + }); + + this.registerDiagnosticsParticipant(new IDiagnosticsParticipant() { + @Override + public void doDiagnostics(DOMDocument xmlDocument, List diagnostics, + XMLValidationSettings validationSettings, CancelChecker cancelChecker) { + throw new RuntimeException("This participant is broken"); + } + }); + this.registerDiagnosticsParticipant(new IDiagnosticsParticipant() { + @Override + public void doDiagnostics(DOMDocument xmlDocument, List diagnostics, + XMLValidationSettings validationSettings, CancelChecker cancelChecker) { + diagnostics.add(TEST_DIAGNOSTIC); + } + }); + + this.registerDocumentLinkParticipant(new IDocumentLinkParticipant() { + @Override + public void findDocumentLinks(DOMDocument document, List links) { + throw new RuntimeException("This participant is broken"); + } + }); + this.registerDocumentLinkParticipant(new IDocumentLinkParticipant() { + @Override + public void findDocumentLinks(DOMDocument document, List links) { + links.add(new DocumentLink(TEST_DOCLINK.getRange(), + Paths.get(TEST_DOCLINK.getTarget()).toUri().toString())); + + } + }); + + this.registerFormatterParticipant(new IFormatterParticipant() { + @Override + public boolean formatAttributeValue(String name, String valueWithoutQuote, Character quote, + DOMAttr attr, XMLBuilder xml) { + throw new RuntimeException("This participant is broken"); + } + }); + + this.registerHighlightingParticipant(new IHighlightingParticipant() { + @Override + public void findDocumentHighlights(DOMNode node, Position position, int offset, + List highlights, CancelChecker cancelChecker) { + throw new RuntimeException("This participant is broken"); + } + }); + this.registerHighlightingParticipant(new IHighlightingParticipant() { + @Override + public void findDocumentHighlights(DOMNode node, Position position, int offset, + List highlights, CancelChecker cancelChecker) { + highlights.add(TEST_HIGHLIGHT); + } + }); + + this.registerHoverParticipant(new IHoverParticipant() { + + @Override + public Hover onTag(IHoverRequest request) throws Exception { + throw new RuntimeException("This participant is broken"); + } + + @Override + public Hover onAttributeName(IHoverRequest request) throws Exception { + throw new RuntimeException("This participant is broken"); + } + + @Override + public Hover onAttributeValue(IHoverRequest request) throws Exception { + throw new RuntimeException("This participant is broken"); + } + + @Override + public Hover onText(IHoverRequest request) throws Exception { + throw new RuntimeException("This participant is broken"); + } + + }); + this.registerHoverParticipant(new IHoverParticipant() { + + @Override + public Hover onTag(IHoverRequest request) throws Exception { + return TEST_HOVER; + } + + @Override + public Hover onAttributeName(IHoverRequest request) throws Exception { + return TEST_HOVER; + } + + @Override + public Hover onAttributeValue(IHoverRequest request) throws Exception { + return TEST_HOVER; + } + + @Override + public Hover onText(IHoverRequest request) throws Exception { + return TEST_HOVER; + } + + }); + + this.registerReferenceParticipant(new IReferenceParticipant() { + @Override + public void findReference(DOMDocument document, Position position, ReferenceContext context, + List locations, CancelChecker cancelChecker) { + throw new RuntimeException("This participant is broken"); + } + }); + this.registerReferenceParticipant(new IReferenceParticipant() { + @Override + public void findReference(DOMDocument document, Position position, ReferenceContext context, + List locations, CancelChecker cancelChecker) { + locations.add(TEST_LOCATION); + } + }); + + this.registerRenameParticipant(new IRenameParticipant() { + @Override + public void doRename(IRenameRequest request, List locations) { + throw new RuntimeException("This participant is broken"); + } + }); + + this.registerSymbolsProviderParticipant(new ISymbolsProviderParticipant() { + + @Override + public SymbolStrategy applyFor(DOMDocument document) { + return SymbolStrategy.INSERT; + } + + @Override + public void findSymbolInformations(DOMDocument document, SymbolInformationResult symbols, + XMLSymbolFilter filter, CancelChecker cancelChecker) { + throw new RuntimeException("This participant is broken"); + } + + @Override + public void findDocumentSymbols(DOMDocument document, DocumentSymbolsResult symbols, + XMLSymbolFilter filter, CancelChecker cancelChecker) { + throw new RuntimeException("This participant is broken"); + } + + }); + this.registerSymbolsProviderParticipant(new ISymbolsProviderParticipant() { + + @Override + public SymbolStrategy applyFor(DOMDocument document) { + return SymbolStrategy.INSERT; + } + + @Override + public void findSymbolInformations(DOMDocument document, SymbolInformationResult symbols, + XMLSymbolFilter filter, CancelChecker cancelChecker) { + symbols.add(TEST_SI); + } + + @Override + public void findDocumentSymbols(DOMDocument document, DocumentSymbolsResult symbols, + XMLSymbolFilter filter, CancelChecker cancelChecker) { + symbols.add(TEST_DS); + } + + }); + this.registerSymbolsProviderParticipant(new ISymbolsProviderParticipant() { + + @Override + public SymbolStrategy applyFor(DOMDocument document) { + return SymbolStrategy.REPLACE; + } + + @Override + public void findSymbolInformations(DOMDocument document, SymbolInformationResult symbols, + XMLSymbolFilter filter, CancelChecker cancelChecker) { + throw new RuntimeException("This participant is broken"); + } + + @Override + public void findDocumentSymbols(DOMDocument document, DocumentSymbolsResult symbols, + XMLSymbolFilter filter, CancelChecker cancelChecker) { + throw new RuntimeException("This participant is broken"); + } + + }); + + this.registerTypeDefinitionParticipant(new ITypeDefinitionParticipant() { + @Override + public void findTypeDefinition(ITypeDefinitionRequest request, List locations, + CancelChecker cancelChecker) { + throw new RuntimeException("This participant is broken"); + } + }); + this.registerTypeDefinitionParticipant(new ITypeDefinitionParticipant() { + @Override + public void findTypeDefinition(ITypeDefinitionRequest request, List locations, + CancelChecker cancelChecker) { + locations.add(TEST_LOCATION_LINK); + } + }); + + } + + } + + // Actual tests + + @Test + public void testCodeAction() throws BadLocationException { + Diagnostic diagnostic = d(0, 0, 2, XMLSyntaxErrorCode.ElementUnterminated); + testCodeActionsFor("", diagnostic, (String) null, null, new ErrorParticipantLanguageService(), + ca(diagnostic, te(0, 0, 0, 0, "a"))); + } + + @Test + public void testCodeLens() throws BadLocationException { + testCodeLensFor("", null, new ErrorParticipantLanguageService(), + ErrorParticipantLanguageService.TEST_CODE_LENS); + } + + @Test + public void testCompletion() throws BadLocationException { + testCompletionFor(new ErrorParticipantLanguageService(), "<|aa bb=\"cc\">dd", null, (a) -> { + }, null, 1, new SharedSettings(), ErrorParticipantLanguageService.TEST_COMPLETION_ITEM); + testCompletionFor(new ErrorParticipantLanguageService(), "dd", null, (a) -> { + }, null, 1, new SharedSettings(), ErrorParticipantLanguageService.TEST_COMPLETION_ITEM); + testCompletionFor(new ErrorParticipantLanguageService(), "dd", null, (a) -> { + }, null, 3, new SharedSettings(), // + ErrorParticipantLanguageService.TEST_COMPLETION_ITEM, // + c("xmlns", "xmlns", r(0, 4, 0, 6), "xmlns"), // + c("xmlns:xsi", "xmlns:xsi", r(0, 4, 0, 6), "xmlns:xsi")); + testCompletionFor(new ErrorParticipantLanguageService(), "dd|", null, (a) -> { + }, null, 4, new SharedSettings(), // + ErrorParticipantLanguageService.TEST_COMPLETION_ITEM); + testCompletionFor(new ErrorParticipantLanguageService(), "", null, (a) -> { + }, null, 1, new SharedSettings(), // + ErrorParticipantLanguageService.TEST_COMPLETION_ITEM); + } + + @Test + public void testDefinition() throws BadLocationException { + testDefinitionFor(new ErrorParticipantLanguageService(), "a|a", null, + ErrorParticipantLanguageService.TEST_LOCATION_LINK); + } + + @Test + public void testDiagnostics() throws BadLocationException { + testDiagnosticsFor(new ErrorParticipantLanguageService(), " { + }, null, false, new ContentModelSettings(), // + ErrorParticipantLanguageService.TEST_DIAGNOSTIC, // + d(0, 1, 0, 2, XMLSyntaxErrorCode.NoGrammarConstraints, "No grammar constraints (DTD or XML Schema).", + "test.xml", DiagnosticSeverity.Hint), // + d(0, 1, 0, 2, XMLSyntaxErrorCode.MarkupEntityMismatch, + "XML document structures must start and end within the same entity.", "xml", + DiagnosticSeverity.Error)); + } + + @Test + public void testDocLinks() throws BadLocationException { + testDocumentLinkFor(new ErrorParticipantLanguageService(), "", null, null, // + ErrorParticipantLanguageService.TEST_DOCLINK); + } + + @Test + public void testFormatting() throws BadLocationException { + assertFormat(new ErrorParticipantLanguageService(), " ", "", new SharedSettings(), + "test://test.html", false); + } + + @Test + public void testHighlight() throws BadLocationException { + assertHighlights(new ErrorParticipantLanguageService(), "|a a", new int[] { 2 }, "a"); + } + + @Test + public void testHover() throws BadLocationException { + assertHover(new ErrorParticipantLanguageService(), "text", null, null, "contents", + r(0, 0, 0, 2)); + assertHover(new ErrorParticipantLanguageService(), "text", null, null, "contents", + r(0, 0, 0, 2)); + assertHover(new ErrorParticipantLanguageService(), "text", null, null, "contents", + r(0, 0, 0, 2)); + assertHover(new ErrorParticipantLanguageService(), "te|xt", null, null, "contents", + r(0, 0, 0, 2)); + } + + @Test + public void testReferences() throws BadLocationException { + testReferencesFor(new ErrorParticipantLanguageService(), "|a", "src/hello", + ErrorParticipantLanguageService.TEST_LOCATION); + } + + @Test + public void testRename() throws BadLocationException { + assertRename(new ErrorParticipantLanguageService(), "<|aa>", "b", + Arrays.asList(te(0, 1, 0, 3, "b"), te(0, 6, 0, 8, "b"))); + } + + @Test + public void testSymbols() throws BadLocationException { + testSymbolInformationsFor(new ErrorParticipantLanguageService(), "e", null, new XMLSymbolSettings(), (a) -> { + }, // + ErrorParticipantLanguageService.TEST_SI); + testDocumentSymbolsFor(new ErrorParticipantLanguageService(), "e", "src/hello", new XMLSymbolSettings(), + (a) -> { + }, // + ErrorParticipantLanguageService.TEST_DS); + } + + @Test + public void testTypeDefinition() throws BadLocationException { + testTypeDefinitionFor(new ErrorParticipantLanguageService(), null, (a) -> { + }, "|a", null, ErrorParticipantLanguageService.TEST_LOCATION_LINK); + } + +}