| author | hbehrens | 2008-11-14 05:09:05 (EST) |
|---|---|---|
| committer | sefftinge | 2008-11-14 05:09:05 (EST) |
| commit | 4326848e260fb4d9e76a7fb98d7f5fac070b4120 (patch) (side-by-side diff) | |
| tree | fdb3b522567b095f5dd4e1e0c9fe9cb3698c4940 | |
| parent | 5009cac601501ce92f324a62703910b4a36db221 (diff) | |
| download | org.eclipse.xtext-4326848e260fb4d9e76a7fb98d7f5fac070b4120.zip org.eclipse.xtext-4326848e260fb4d9e76a7fb98d7f5fac070b4120.tar.gz org.eclipse.xtext-4326848e260fb4d9e76a7fb98d7f5fac070b4120.tar.bz2 | |
Redesign of linking phase with respect to performance (Huge patch from Sebastian), Refers to Bug 255037, Bug 254995 and Bug 254859
8 files changed, 345 insertions, 116 deletions
diff --git a/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/AbstractProposalProvider.java b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/AbstractProposalProvider.java index 609579e..3beacaf 100644 --- a/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/AbstractProposalProvider.java +++ b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/AbstractProposalProvider.java @@ -8,7 +8,6 @@ import java.util.List; import java.util.Map; import org.apache.log4j.Logger; -import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.contentassist.ICompletionProposal; @@ -22,6 +21,7 @@ import org.eclipse.xtext.Keyword; import org.eclipse.xtext.LexerRule; import org.eclipse.xtext.ParserRule; import org.eclipse.xtext.RuleCall; +import org.eclipse.xtext.crossref.ILinkingNameService; import org.eclipse.xtext.crossref.ILinkingService; import org.eclipse.xtext.parsetree.AbstractNode; import org.eclipse.xtext.parsetree.CompositeNode; @@ -29,7 +29,7 @@ import org.eclipse.xtext.parsetree.LeafNode; import org.eclipse.xtext.parsetree.NodeUtil; import org.eclipse.xtext.parsetree.ParseTreeUtil; import org.eclipse.xtext.service.Inject; -import org.eclipse.xtext.util.Pair; +import org.eclipse.xtext.util.Strings; /** * Convenient super class for <code>IProposalProvider</code> implementations. @@ -50,9 +50,15 @@ public abstract class AbstractProposalProvider implements IProposalProvider { @Inject protected ILinkingService linkingService; + @Inject + protected ILinkingNameService linkingNameService; + /* * (non-Javadoc) - * @see org.eclipse.xtext.ui.common.editor.codecompletion.IProposalProvider#completeKeyword(org.eclipse.xtext.Keyword, org.eclipse.emf.ecore.EObject, java.lang.String, org.eclipse.jface.text.IDocument, int) + * + * @see + * org.eclipse.xtext.ui.common.editor.codecompletion.IProposalProvider#completeKeyword(org.eclipse.xtext.Keyword, + * org.eclipse.emf.ecore.EObject, java.lang.String, org.eclipse.jface.text.IDocument, int) */ public List<? extends ICompletionProposal> completeKeyword(Keyword keyword, EObject model, String prefix, IDocument doc, int offset) { @@ -66,7 +72,10 @@ public abstract class AbstractProposalProvider implements IProposalProvider { /* * (non-Javadoc) - * @see org.eclipse.xtext.ui.common.editor.codecompletion.IProposalProvider#completeRuleCall(org.eclipse.xtext.RuleCall, org.eclipse.emf.ecore.EObject, java.lang.String, org.eclipse.jface.text.IDocument, int) + * + * @see + * org.eclipse.xtext.ui.common.editor.codecompletion.IProposalProvider#completeRuleCall(org.eclipse.xtext.RuleCall, + * org.eclipse.emf.ecore.EObject, java.lang.String, org.eclipse.jface.text.IDocument, int) */ public List<? extends ICompletionProposal> completeRuleCall(RuleCall ruleCall, EObject model, String prefix, IDocument doc, int offset) { @@ -84,10 +93,12 @@ public abstract class AbstractProposalProvider implements IProposalProvider { return Collections.emptyList(); } - /* * (non-Javadoc) - * @see org.eclipse.xtext.ui.common.editor.codecompletion.IProposalProvider#sortAndFilter(java.util.List, org.eclipse.emf.ecore.EObject, java.lang.String, org.eclipse.jface.text.IDocument, int, org.eclipse.xtext.parsetree.AbstractNode, org.eclipse.xtext.parsetree.LeafNode) + * + * @see org.eclipse.xtext.ui.common.editor.codecompletion.IProposalProvider#sortAndFilter(java.util.List, + * org.eclipse.emf.ecore.EObject, java.lang.String, org.eclipse.jface.text.IDocument, int, + * org.eclipse.xtext.parsetree.AbstractNode, org.eclipse.xtext.parsetree.LeafNode) */ public List<? extends ICompletionProposal> sortAndFilter( List<? extends ICompletionProposal> completionProposalList, EObject model, String prefix, @@ -96,25 +107,21 @@ public abstract class AbstractProposalProvider implements IProposalProvider { } /** - * Concrete subclasses can override this to provide a more meaningful and - * sophisticated behaviour whenever a list of ICompletionProposal's should - * be computed for simple <code>LexerRule</code> call's. + * Concrete subclasses can override this to provide a more meaningful and sophisticated behaviour whenever a list of + * ICompletionProposal's should be computed for simple <code>LexerRule</code> call's. * - * This implementation returns one <code>ICompletionProposal</code> with a - * displayString composed of the name of the containing rule plus the - * featurename of an optional assignment and at the end the name of the - * given LexerRule (e.i. ParserRuleName+AssignmentFeatureName+LexerRuleName) - * or {@link #getDefaultIntegerValue()} if its <i>INT</i> based LexerRule. + * This implementation returns one <code>ICompletionProposal</code> with a displayString composed of the name of the + * containing rule plus the featurename of an optional assignment and at the end the name of the given LexerRule + * (e.i. ParserRuleName+AssignmentFeatureName+LexerRuleName) or {@link #getDefaultIntegerValue()} if its <i>INT</i> + * based LexerRule. * * @param lexerRule * the 'called' LexerRule instance * @param ruleCall * the ruleCall for the provided lexerRule * @param offset - * an offset within the document for which completions should be - * computed - * @return a computed list of <code>ICompletionProposal</code> for the given - * <code>LexerRule</code> + * an offset within the document for which completions should be computed + * @return a computed list of <code>ICompletionProposal</code> for the given <code>LexerRule</code> */ protected List<? extends ICompletionProposal> doCompleteLexerRuleRuleCall(LexerRule lexerRule, RuleCall ruleCall, EObject model, int offset) { @@ -145,30 +152,26 @@ public abstract class AbstractProposalProvider implements IProposalProvider { /** * - * @return the id of the plug-in containing the image files; <code>null - * </code> is returned if the plug-in does not exist + * @return the id of the plug-in containing the image files; <code>null </code> is returned if the plug-in does not + * exist */ protected abstract String getPluginId(); /** - * Returns the the relative path of the default image file, relative to the - * root of the containing plug-in; the path must be legal The image would - * typically be shown to the left of the <code>ICompletionProposal</code> - * display string. + * Returns the the relative path of the default image file, relative to the root of the containing plug-in; the path + * must be legal The image would typically be shown to the left of the <code>ICompletionProposal</code> display + * string. * - * @return the image file path of the default image to be shown or - * <code>null</code> if no image is desired + * @return the image file path of the default image to be shown or <code>null</code> if no image is desired * @see #getPluginId() */ protected abstract String getDefaultImageFilePath(); /** - * Concrete subclasses can override this to provide custom lookup behaviour - * for <code>CrossReference</code>. This implementation delegates to the - * injected LinkingService + * Concrete subclasses can override this to provide custom lookup behaviour for <code>CrossReference</code>. This + * implementation delegates to the injected LinkingService * - * @return a list of <code>ICompletionProposal</code> matching the given - * assignment + * @return a list of <code>ICompletionProposal</code> matching the given assignment */ protected List<? extends ICompletionProposal> lookupCrossReference(CrossReference crossReference, EObject model, String prefix, int offset) { @@ -176,11 +179,10 @@ public abstract class AbstractProposalProvider implements IProposalProvider { List<ICompletionProposal> completionProposalList = new ArrayList<ICompletionProposal>(); if (linkingService != null) { - List<Pair<String, URI>> candidates = linkingService - .getLinkCandidates(model, crossReference, prefix); - for (Pair<String, URI> candidate : candidates) { - completionProposalList.add(createCompletionProposal(crossReference, model, candidate.getFirstElement(), - offset)); + List<EObject> candidates = linkingService.getLinkCandidates(model, crossReference, prefix); + for (EObject candidate : candidates) { + completionProposalList.add(createCompletionProposal(crossReference, model, linkingNameService.getText( + candidate, crossReference), offset)); } } @@ -188,46 +190,47 @@ public abstract class AbstractProposalProvider implements IProposalProvider { } /** - * @return a new <code>XtextCompletionProposal</code> for the given text and - * offset. + * @return a new <code>XtextCompletionProposal</code> for the given text and offset. */ protected final XtextCompletionProposal createCompletionProposal(AbstractElement abstractElement, EObject model, String text, int offset) { return new XtextCompletionProposal(abstractElement, model, text, new StyledString(text), text, getDefaultImageFilePath(), getPluginId(), offset); } - + /** - * Concrete subclasses can override this for custom sort and filter - * behavior. Gets called after all completion proposals have been collected. + * Concrete subclasses can override this for custom sort and filter behavior. Gets called after all completion + * proposals have been collected. * - * The default behavior of this implementation is to sort duplicates and to - * trim matching <code>ICompletionProposal#displayString</code> with matching prefix values. + * The default behavior of this implementation is to sort duplicates and to trim matching + * <code>ICompletionProposal#displayString</code> with matching prefix values. * - * @see #sortAndFilter(List, EObject, String, IDocument, int, AbstractNode, LeafNode) + * @see #sortAndFilter(List, EObject, String, IDocument, int, AbstractNode, LeafNode) */ protected List<? extends ICompletionProposal> doSortAndFilter( - List<? extends ICompletionProposal> completionProposalList, EObject model, String prefix,IDocument document, int offset) { + List<? extends ICompletionProposal> completionProposalList, EObject model, String prefix, + IDocument document, int offset) { Map<String, ICompletionProposal> displayString2ICompletionProposalMap = new HashMap<String, ICompletionProposal>(); - + for (Iterator<? extends ICompletionProposal> iterator = completionProposalList.iterator(); iterator.hasNext();) { ICompletionProposal completionProposal = iterator.next(); - + // filter duplicate displayString if (!displayString2ICompletionProposalMap.containsKey(completionProposal.getDisplayString())) { displayString2ICompletionProposalMap.put(completionProposal.getDisplayString(), completionProposal); - + if (model != null) { - + CompositeNode parserNode = NodeUtil.getRootNode(model); - - LeafNode currentLeafNode=ParseTreeUtil.getCurrentNodeByOffset(parserNode, offset); - boolean isCursorAtTheEndOfTheLastElement = offset == (currentLeafNode.getOffset() + currentLeafNode.getLength()); - + LeafNode currentLeafNode = ParseTreeUtil.getCurrentNodeByOffset(parserNode, offset); + + boolean isCursorAtTheEndOfTheLastElement = offset == (currentLeafNode.getOffset() + currentLeafNode + .getLength()); + if (isCursorAtTheEndOfTheLastElement && completionProposal instanceof XtextCompletionProposal) { XtextCompletionProposal xtextCompletionProposal = (XtextCompletionProposal) completionProposal; @@ -236,16 +239,16 @@ public abstract class AbstractProposalProvider implements IProposalProvider { EObject grammarElement = currentLeafNode.getGrammarElement(); // at the end of the last element we want to filter only the CompletionProposal for the same grammar element - if (((isCursorAtTheEndOfTheLastElement && abstractElement.equals(grammarElement)) - || !isCursorAtTheEndOfTheLastElement) && !completionProposal.getDisplayString().startsWith(currentLeafNode.getText())) { + if (((isCursorAtTheEndOfTheLastElement && abstractElement.equals(grammarElement)) || !isCursorAtTheEndOfTheLastElement) + && !completionProposal.getDisplayString().startsWith(currentLeafNode.getText())) { if (logger.isDebugEnabled()) { logger.debug("filter completionProposal '" + completionProposal + "'"); } iterator.remove(); } - } + } } - + } else { if (logger.isDebugEnabled()) { @@ -255,7 +258,6 @@ public abstract class AbstractProposalProvider implements IProposalProvider { iterator.remove(); } } - return completionProposalList; } @@ -266,10 +268,7 @@ public abstract class AbstractProposalProvider implements IProposalProvider { * @return the provided string with the first letter capitalized */ protected final String firstLetterCapitalized(String text) { - if (text == null || text.length() == 0) { - return text; - } - return text.substring(0, 1).toUpperCase() + text.substring(1, text.length()); + return Strings.toFirstUpper(text); } } diff --git a/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/DefaultContentAssistProcessor.java b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/DefaultContentAssistProcessor.java index 6331160..84223db 100644 --- a/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/DefaultContentAssistProcessor.java +++ b/plugins/org.eclipse.xtext.ui.common/src/org/eclipse/xtext/ui/common/editor/codecompletion/DefaultContentAssistProcessor.java @@ -8,7 +8,6 @@ import java.util.Set; import org.apache.log4j.Logger; import org.eclipse.core.runtime.Assert; import org.eclipse.emf.common.util.EList; -import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; @@ -49,18 +48,18 @@ public class DefaultContentAssistProcessor implements IContentAssistProcessor { @Inject private IProposalProvider proposalProvider; - /** - * @param proposalProvider the proposalProvider to set + * @param proposalProvider + * the proposalProvider to set */ public void setProposalProvider(IProposalProvider proposalProvider) { this.proposalProvider = proposalProvider; } /** - * computes the possible grammar elements following the one at the given - * offset and calls the respective methods on the proposal provider. + * computes the possible grammar elements following the one at the given offset and calls the respective methods on + * the proposal provider. */ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, final int offset) { @@ -97,8 +96,8 @@ public class DefaultContentAssistProcessor implements IContentAssistProcessor { Set<AbstractElement> nextValidElementSet = new LinkedHashSet<AbstractElement>(); /** - * in case of a crossreference which isnt linked already we - * evaluate it again and delegate to proposalProvider (again) + * in case of a crossreference which isnt linked already we evaluate it again and delegate to + * proposalProvider (again) */ if (lastCompleteNode.getGrammarElement() instanceof CrossReference && !isLinked(lastCompleteNode)) { nextValidElementSet.add((AbstractElement) lastCompleteNode.getGrammarElement()); @@ -106,9 +105,8 @@ public class DefaultContentAssistProcessor implements IContentAssistProcessor { offset)); } /** - * in case of 'at-the-end' of the previous,completed element we - * evaluate it again for 'right-to-left-backtracking' cases - * (e.g. for keyword 'kind' kind>|< |=cursorpos) + * in case of 'at-the-end' of the previous,completed element we evaluate it again for + * 'right-to-left-backtracking' cases (e.g. for keyword 'kind' kind>|< |=cursorpos) */ else if (currentLeafNode == lastCompleteNode) { nextValidElementSet = ParseTreeUtil @@ -195,19 +193,17 @@ public class DefaultContentAssistProcessor implements IContentAssistProcessor { EReference eReference = getReference(crossReference, semanticModel.eClass()); List<EObject> referencedObjects = EcoreUtil2.getAllReferencedObjects(semanticModel, eReference); - + if (referencedObjects.isEmpty()) return false; else { - List<URI> referencedURIs = EcoreUtil2.getURIs(referencedObjects); - List<URI> linkCandidates = linkingService.getLinkedObjects(semanticModel, crossReference, + List<EObject> linkCandidates = linkingService.getLinkedObjects(semanticModel, crossReference, (LeafNode) lastCompleteNode); - return !linkCandidates.isEmpty() && referencedURIs.containsAll(linkCandidates); + return !linkCandidates.isEmpty() && referencedObjects.containsAll(linkCandidates); } } private EReference getReference(CrossReference ref, EClass class1) { - EList<EReference> references = class1.getEAllReferences(); String feature = GrammarUtil.containingAssignment(ref).getFeature(); diff --git a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/crossrefs/CrossRefTest.java b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/crossrefs/CrossRefTest.java index e4fa850..8990216 100644 --- a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/crossrefs/CrossRefTest.java +++ b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/crossrefs/CrossRefTest.java @@ -3,77 +3,67 @@ package org.eclipse.xtext.crossrefs; import java.util.List; import org.apache.log4j.Logger; -import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.xtext.Assignment; import org.eclipse.xtext.CrossReference; import org.eclipse.xtext.Group; import org.eclipse.xtext.ParserRule; import org.eclipse.xtext.crossref.ILinkingService; +import org.eclipse.xtext.crossref.impl.XtextBuiltinLinkingService; import org.eclipse.xtext.crossrefs.services.LangAGrammarAccess; import org.eclipse.xtext.service.ServiceRegistry; import org.eclipse.xtext.tests.AbstractGeneratorTest; -import org.eclipse.xtext.util.Pair; public class CrossRefTest extends AbstractGeneratorTest { private static final Logger logger = Logger.getLogger(CrossRefTest.class); - private ILinkingService linkingService; - + private XtextBuiltinLinkingService linkingService; + @Override protected void setUp() throws Exception { super.setUp(); with(LangAStandaloneSetup.class); - linkingService = ServiceRegistry.getService(ILangA.SCOPE, ILinkingService.class); + linkingService = (XtextBuiltinLinkingService) ServiceRegistry.getService(ILangA.SCOPE, ILinkingService.class); } - + public void testSimple() throws Exception { EObject model = getModel("type A extends B type B extends A"); logger.debug(invokeWithXtend("types.collect(e|e.name+' '+e.extends.name).toString(',')", model)); assertWithXtend("'B'", "types.first().extends.name", model); assertWithXtend("types.first()", "types.first().extends.extends", model); } - - public void testGetLinkText() throws Exception { - EObject model = getModel("type A extends B type B extends A"); - EObject typeA = model.eResource().getEObject("A"); - EObject typeB = model.eResource().getEObject("B"); - URI uriA = EcoreUtil.getURI(typeA); - URI uriB = EcoreUtil.getURI(typeB); - assertEquals("A", linkingService.getLinkAsText(typeA, uriA)); - assertEquals("B", linkingService.getLinkAsText(typeA, uriB)); - assertEquals("A", linkingService.getLinkAsText(typeB, uriA)); - assertEquals("B", linkingService.getLinkAsText(typeB, uriB)); - } - + public void testGetLinkCandidates01() throws Exception { EObject model = getModel("type TypeA extends TypeB type TypeB extends TypeA type AnotherType extends TypeA"); - + assertWithXtend("3", "types.size", model); - + EObject context = (EObject) invokeWithXtend("types.first()", model); ParserRule prType = new LangAGrammarAccess().pr_Type(); - Assignment asExtends = (Assignment)((Group)prType.getAlternatives()).getAbstractTokens().get(1); + Assignment asExtends = (Assignment) ((Group) prType.getAlternatives()).getAbstractTokens().get(1); CrossReference xref = (CrossReference) asExtends.getTerminal(); - - assertEquals(3, linkingService.getLinkCandidates(context, xref, "").size()); - assertEquals(2, linkingService.getLinkCandidates(context, xref, "Type").size()); - assertEquals(1, linkingService.getLinkCandidates(context, xref, "TypeA").size()); - assertEquals(0, linkingService.getLinkCandidates(context, xref, "TypeC").size()); + + assertEquals(3, linkingService.doGetLinkedObjects(context, xref, "", false).size()); + assertEquals(2, linkingService.doGetLinkedObjects(context, xref, "Type", false).size()); + assertEquals(1, linkingService.doGetLinkedObjects(context, xref, "TypeA", false).size()); + assertEquals(0, linkingService.doGetLinkedObjects(context, xref, "TypeC", false).size()); } - + public void testGetLinkCandidates02() throws Exception { EObject model = getModel("type TypeA extends TypeB type TypeB extends TypeA type AnotherType extends TypeA"); - + EObject context = (EObject) invokeWithXtend("types.first()", model); ParserRule prType = new LangAGrammarAccess().pr_Type(); - Assignment asExtends = (Assignment)((Group)prType.getAlternatives()).getAbstractTokens().get(1); + Assignment asExtends = (Assignment) ((Group) prType.getAlternatives()).getAbstractTokens().get(1); CrossReference xref = (CrossReference) asExtends.getTerminal(); - - List<Pair<String, URI>> candidates = linkingService.getLinkCandidates(context, xref, "TypeA"); + + List<EObject> candidates = linkingService.getLinkCandidates(context, xref, "TypeA"); assertEquals(1, candidates.size()); - Pair<String, URI> candidate = candidates.get(0); - assertEquals("TypeA", candidate.getFirstElement()); - assertEquals(model.eResource().getURI().appendFragment("TypeA"), candidate.getSecondElement()); + EObject candidate = candidates.get(0); + EStructuralFeature feature = candidate.eClass().getEStructuralFeature("name"); + assertNotNull(feature); + Object name = candidate.eGet(feature); + assertNotNull(name); + assertEquals("TypeA", name); } } diff --git a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/generator/AutoTestSuite.java b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/generator/AutoTestSuite.java index 72d0993..1227d21 100644 --- a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/generator/AutoTestSuite.java +++ b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/generator/AutoTestSuite.java @@ -46,6 +46,7 @@ public class AutoTestSuite { suite.addTestSuite(org.eclipse.xtext.resource.metamodel.TypeHierarchyHelperTests.class); suite.addTestSuite(org.eclipse.xtext.crossrefs.CrossRefTest.class); suite.addTestSuite(org.eclipse.xtext.crossrefs.LinkingErrorTest.class); + suite.addTestSuite(org.eclipse.xtext.util.SimpleCacheTest.class); return suite; } } diff --git a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/resource/XtextResourcePerformanceTest.java b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/resource/XtextResourcePerformanceTest.java new file mode 100644 index 0000000..d6758b1 --- a/dev/null +++ b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/resource/XtextResourcePerformanceTest.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2008 itemis AG (http://www.itemis.eu) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.resource; + +import org.eclipse.xtext.testlanguages.ReferenceGrammarStandaloneSetup; +import org.eclipse.xtext.tests.AbstractGeneratorTest; + +/** + * @author Sebastian Zarnekow - Initial contribution and API + */ +public class XtextResourcePerformanceTest extends AbstractGeneratorTest { + + private static final int NUM_ELEMENTS = 100; + private String model; + + protected void setUp() throws Exception { + super.setUp(); + with(ReferenceGrammarStandaloneSetup.class); + StringBuilder modelBuilder = new StringBuilder(NUM_ELEMENTS * 64); + modelBuilder.append("spielplatz " + NUM_ELEMENTS + " {\r\n"); + for(int i = 1; i <= NUM_ELEMENTS; i++ ) { + modelBuilder.append(" kind (Bob" + i + " " + i + ")\r\n"); + modelBuilder.append(" kind (Joe" + i + " " + i + ")\r\n"); + modelBuilder.append(" erwachsener (Mutter" + i + " " + i + ")\r\n"); + modelBuilder.append(" erwachsener (Vater" + i + " " + i + ")\r\n"); + modelBuilder.append(" familie(Familie" + i + " Vater" + i + " Mutter" + i + " Bob" + i + ", Joe" + i + ")\r\n"); + } + modelBuilder.append('}'); + model = modelBuilder.toString(); + } + + public void testLoad() throws Exception { + XtextResource resource = getResourceFromString(model); + assertNotNull(resource); + assertTrue(resource.getParseResult().getParseErrors().isEmpty()); + } + + public void testLoadModelWithLinkingErrors() throws Exception { + StringBuilder modelBuilder = new StringBuilder(NUM_ELEMENTS * 64); + modelBuilder.append("spielplatz " + NUM_ELEMENTS + " {\r\n"); + for(int i = 1; i <= NUM_ELEMENTS; i++ ) { + modelBuilder.append(" kind (Bob " + i + ")\r\n"); + modelBuilder.append(" kind (Joe " + i + ")\r\n"); + modelBuilder.append(" erwachsener (Mutter " + i + ")\r\n"); + modelBuilder.append(" erwachsener (Vater " + i + ")\r\n"); + modelBuilder.append(" familie(Familie" + i + " Vater Mutter Bob, Joe)\r\n"); + } + modelBuilder.append('}'); + model = modelBuilder.toString(); + XtextResource resource = getResourceFromString(model); + assertNotNull(resource); + assertTrue(resource.getParseResult().getParseErrors().isEmpty()); + assertEquals(2 * NUM_ELEMENTS, resource.getErrors().size()); + } + +} diff --git a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/resource/XtextResourceTest.java b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/resource/XtextResourceTest.java new file mode 100644 index 0000000..1e8a46b --- a/dev/null +++ b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/resource/XtextResourceTest.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2008 itemis AG (http://www.itemis.eu) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.resource; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.xtext.parser.IParseResult; +import org.eclipse.xtext.testlanguages.ReferenceGrammarStandaloneSetup; +import org.eclipse.xtext.tests.AbstractGeneratorTest; + +/** + * @author Sebastian Zarnekow - Initial contribution and API + */ +public class XtextResourceTest extends AbstractGeneratorTest { + + private XtextResource resource; + private String simpleModel = "spielplatz 1 { kind ( Bob 0 ) }"; + + protected void setUp() throws Exception { + super.setUp(); + with(ReferenceGrammarStandaloneSetup.class); + resource = getResourceFromString(""); + } + + public void testInitialState() throws Exception { + assertNotNull(resource); + assertTrue(resource.isLoaded()); + assertFalse("resource.isTrackingModification()", resource.isTrackingModification()); + assertFalse(resource.isModified()); + assertTrue(resource.getErrors().isEmpty()); + assertTrue(resource.getWarnings().isEmpty()); + + IParseResult parseResult = resource.getParseResult(); + assertNotNull("parseResult", parseResult); + assertNotNull(parseResult.getRootNode()); + assertEquals(0, parseResult.getParseErrors().size()); + assertEquals(0, parseResult.getRootNode().getLength()); + assertNull(parseResult.getRootASTElement()); + } + + public void testModify_01() throws Exception { + resource.update(0, 0, simpleModel); + assertFalse(resource.isModified()); + } + + public void testModify_02() throws Exception { + resource.reparse(simpleModel); + assertFalse(resource.isModified()); + } + + public void testModify_03() throws Exception { + resource.reparse(simpleModel); + assertFalse(resource.isModified()); + modifySpielplatz(); + assertFalse(resource.isModified()); + } + + public void testModify_04() throws Exception { + resource.setTrackingModification(true); + resource.update(0, 0, simpleModel); + assertFalse(resource.isModified()); + } + + public void testModify_05() throws Exception { + resource.setTrackingModification(true); + resource.reparse(simpleModel); + assertFalse(resource.isModified()); + } + + public void testModify_06() throws Exception { + resource.setTrackingModification(true); + resource.reparse(simpleModel); + assertFalse(resource.isModified()); + modifySpielplatz(); + assertTrue(resource.isModified()); + } + + private void modifySpielplatz() { + EObject obj = resource.getParseResult().getRootASTElement(); + assertNotNull(obj); + assertEquals("Spielplatz", obj.eClass().getName()); + EStructuralFeature feature = obj.eClass().getEStructuralFeature("groesse"); + assertNotNull(feature); + assertEquals(1, obj.eGet(feature)); + obj.eSet(feature, 3); + } + + public void testUnload() throws Exception { + resource.reparse(simpleModel); + IParseResult parseResult = resource.getParseResult(); + resource.unload(); + assertNull(resource.getParseResult()); + assertTrue(parseResult.getRootASTElement().eIsProxy()); + } + + public void testUpdate() throws Exception { + resource.update(0, 0, simpleModel); + + IParseResult parseResult = resource.getParseResult(); + assertNotNull("parseResult", parseResult); + assertNotNull(parseResult.getRootNode()); + assertEquals(0, parseResult.getParseErrors().size()); + assertEquals(simpleModel.length(), parseResult.getRootNode().getLength()); + assertNotNull(parseResult.getRootASTElement()); + } + + +} diff --git a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/resource/metamodel/ResourceTests.java b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/resource/metamodel/ResourceTests.java index f6a694d..a89ad76 100644 --- a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/resource/metamodel/ResourceTests.java +++ b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/resource/metamodel/ResourceTests.java @@ -24,10 +24,8 @@ public class ResourceTests extends AbstractGeneratorTest { public void testFragmentsWorkInBothDirections() throws Exception { EObject model = getModel("type A extends B type B extends A"); EObject typeA1 = (EObject) invokeWithXtend("types.first()", model); - EObject typeA2 = model.eResource().getEObject("A"); + EObject typeA2 = model.eResource().getEObject(model.eResource().getURIFragment(typeA1)); assertEquals(typeA1, typeA2); - String uriFrament = model.eResource().getURIFragment(typeA1); - assertEquals("A", uriFrament); } } diff --git a/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/util/SimpleCacheTest.java b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/util/SimpleCacheTest.java new file mode 100644 index 0000000..bbaa495 --- a/dev/null +++ b/tests/org.eclipse.xtext.generator.tests/src/org/eclipse/xtext/util/SimpleCacheTest.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2008 itemis AG (http://www.itemis.eu) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + *******************************************************************************/ +package org.eclipse.xtext.util; + +import junit.framework.TestCase; + +/** + * @author Sebastian Zarnekow - Initial contribution and API + */ +public class SimpleCacheTest extends TestCase implements Function<String, String>{ + + private SimpleCache<String, String> cache; + + private String expectedParam; + + private int callCount; + + protected void setUp() throws Exception { + this.cache = new SimpleCache<String, String>(this); + expectedParam = null; + callCount = 0; + } + + public String exec(String param) { + assertEquals(expectedParam, param); + callCount++; + return param + param; + } + + public void testInitial() { + assertEquals(0, cache.getSize()); + } + + public void testGet() { + expectedParam = new String("param"); // is not interned + String cached = cache.get(expectedParam); + assertEquals("paramparam", cached); + assertEquals(1, callCount); + assertEquals(1, cache.getSize()); + assertSame(cached, cache.get(new String(expectedParam))); + assertEquals(1, callCount); + assertEquals(1, cache.getSize()); + } + + public void testDiscard() { + String first = new String("first"); // is not interned + expectedParam = first; + cache.get(expectedParam); + String second = new String("second"); // is not interned + expectedParam = second; + cache.get(expectedParam); + assertEquals(2, cache.getSize()); + cache.discard(expectedParam); + assertEquals(1, cache.getSize()); + assertFalse(cache.hasCachedValue(expectedParam)); + } + + public void testClear() { + expectedParam = new String("param"); // is not interned + cache.get(expectedParam); + assertEquals(1, cache.getSize()); + cache.clear(); + assertEquals(0, cache.getSize()); + } + +} |

