[287082] Fix: Don’t loose information about bogus cardinality

Also support /* Suppress[issueCodeSuffix] */ in Xtext 
grammars.

https://bugs.eclipse.org/bugs/show_bug.cgi?id=287082
This commit is contained in:
Sebastian Zarnekow 2015-07-02 11:27:45 +02:00
parent ce4e7824a2
commit d7ce46fa57
39 changed files with 391 additions and 13 deletions

View file

@ -269,17 +269,12 @@ public abstract class AbstractXtextTests extends Assert implements ResourceLoadH
if (d instanceof ExceptionDiagnostic)
fail(d.getMessage());
}
for(Diagnostic d: resource.getWarnings())
System.out.println("Resource Warning: "+d);
if (expectedErrors == 0 && resource.getContents().size() > 0 && shouldTestSerializer(resource)) {
SerializerTester tester = get(SerializerTester.class);
EObject obj = resource.getContents().get(0);
tester.assertSerializeWithNodeModel(obj);
tester.assertSerializeWithoutNodeModel(obj);
}
return resource;
}

View file

@ -80,7 +80,8 @@ Export-Package: org.eclipse.xtext,
org.eclipse.xtext.validation.impl,
org.eclipse.xtext.workspace;x-friends:="org.eclipse.xtext.xbase.ui",
org.eclipse.xtext.xtext;x-friends:="org.eclipse.xtext.xtext.ui",
org.eclipse.xtext.xtext.ecoreInference;x-internal:=true
org.eclipse.xtext.xtext.ecoreInference;x-internal:=true,
org.eclipse.xtext.xtext.parser;x-friends:="org.eclipse.xtext.tests"
Require-Bundle: org.eclipse.emf.ecore.xmi;bundle-version="2.10.2";visibility:=reexport,
org.eclipse.emf.ecore;bundle-version="2.10.2";visibility:=reexport,
org.eclipse.emf.codegen;bundle-version="2.10.0";resolution:=optional;x-installation:=greedy,

View file

@ -62,6 +62,7 @@ AbstractToken returns AbstractElement:
Action
;
/* Suppress[potentialOverride]: Handled in CardinalityAwareEcoreFactory */
AbstractTokenWithCardinality returns AbstractElement:
(Assignment | AbstractTerminal) (cardinality=('?'|'*'|'+'))?
;
@ -148,6 +149,7 @@ TerminalGroup returns AbstractElement:
TerminalToken ({Group.elements+=current} (elements+=TerminalToken)+)?
;
/* Suppress[potentialOverride]: Handled in CardinalityAwareEcoreFactory */
TerminalToken returns AbstractElement:
TerminalTokenElement (cardinality=('?'|'*'|'+'))?
;

View file

@ -14,7 +14,9 @@ import org.eclipse.xtext.linking.ILinker;
import org.eclipse.xtext.linking.ILinkingDiagnosticMessageProvider;
import org.eclipse.xtext.linking.ILinkingService;
import org.eclipse.xtext.naming.IQualifiedNameConverter;
import org.eclipse.xtext.parser.DefaultEcoreElementFactory;
import org.eclipse.xtext.parser.antlr.IReferableElementsUnloader;
import org.eclipse.xtext.parser.antlr.SyntaxErrorMessageProvider;
import org.eclipse.xtext.parsetree.reconstr.ITokenSerializer.ICrossReferenceSerializer;
import org.eclipse.xtext.parsetree.reconstr.ITransientValueService;
import org.eclipse.xtext.resource.DerivedStateAwareResourceDescriptionManager;
@ -48,6 +50,8 @@ import org.eclipse.xtext.xtext.XtextValidator;
import org.eclipse.xtext.xtext.XtextValueConverters;
import org.eclipse.xtext.xtext.ecoreInference.IXtext2EcorePostProcessor;
import org.eclipse.xtext.xtext.ecoreInference.XtendXtext2EcorePostProcessor;
import org.eclipse.xtext.xtext.parser.CardinalityAwareEcoreFactory;
import org.eclipse.xtext.xtext.parser.CardinalityAwareSyntaxErrorMessageProvider;
import com.google.inject.Binder;
@ -164,4 +168,18 @@ public class XtextRuntimeModule extends AbstractXtextRuntimeModule {
public Class<? extends ConfigurableIssueCodesProvider> bindConfigurableIssueCodesProvider() {
return XtextConfigurableIssueCodes.class;
}
/**
* @since 2.9
*/
public Class<? extends DefaultEcoreElementFactory> bindCardinalityAwareFactory() {
return CardinalityAwareEcoreFactory.class;
}
/**
* @since 2.9
*/
public Class<? extends SyntaxErrorMessageProvider> bindSyntaxErrorMessageProvider() {
return CardinalityAwareSyntaxErrorMessageProvider.class;
}
}

View file

@ -7,10 +7,16 @@
*******************************************************************************/
package org.eclipse.xtext.xtext;
import java.util.List;
import org.eclipse.emf.common.util.EList;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.SyntaxErrorMessage;
import org.eclipse.xtext.parser.IParseResult;
import org.eclipse.xtext.resource.DerivedStateAwareResource;
import org.eclipse.xtext.resource.IDerivedStateComputer;
import org.eclipse.xtext.resource.XtextSyntaxDiagnostic;
import org.eclipse.xtext.xtext.parser.CardinalityAwareSyntaxErrorMessageProvider;
/**
* Resource implementation that instantiates the infered packages as part of the
@ -62,6 +68,19 @@ public class GrammarResource extends DerivedStateAwareResource {
return super.getWarnings();
}
/**
* @since 2.9
*/
@Override
protected void addSyntaxDiagnostic(List<Diagnostic> diagnostics, INode node) {
SyntaxErrorMessage syntaxErrorMessage = node.getSyntaxErrorMessage();
if (CardinalityAwareSyntaxErrorMessageProvider.CARDINALITY_ISSUE.equals(syntaxErrorMessage.getIssueCode())) {
super.getWarnings().add(new XtextSyntaxDiagnostic(node));
} else {
super.addSyntaxDiagnostic(diagnostics, node);
}
}
/**
* Triggers the ecore inference as soon as someone wants to access the contents
* of a {@link GrammarResource}.

View file

@ -34,6 +34,8 @@ import com.google.common.collect.Sets;
*/
public class OverriddenValueInspector extends XtextRuleInspector<Boolean, ParserRule> {
public static final String ISSUE_CODE = "OverriddenValueInspector.potentialOverride";
private Multimap<String, AbstractElement> assignedFeatures;
/**
@ -48,6 +50,11 @@ public class OverriddenValueInspector extends XtextRuleInspector<Boolean, Parser
permanentlyVisited = Sets.newHashSet();
}
@Override
protected String getIssueCode() {
return ISSUE_CODE;
}
@Override
public boolean addVisited(AbstractRule rule) {
return permanentlyVisited.add(rule) && super.addVisited(rule);

View file

@ -27,10 +27,17 @@ import org.eclipse.xtext.validation.ValidationMessageAcceptor;
*/
public class RuleWithoutInstantiationInspector extends XtextRuleInspector<Boolean, ParserRule> {
public static final String ISSUE_CODE = "RuleWithoutInstantiationInspector.noInstantiation";
public RuleWithoutInstantiationInspector(ValidationMessageAcceptor acceptor) {
super(acceptor);
}
@Override
protected String getIssueCode() {
return ISSUE_CODE;
}
@Override
protected boolean canInspect(ParserRule rule) {
// special treatment of first rule

View file

@ -7,9 +7,17 @@
*******************************************************************************/
package org.eclipse.xtext.xtext;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.xtext.AbstractRule;
import org.eclipse.xtext.GrammarUtil;
import org.eclipse.xtext.diagnostics.Severity;
import org.eclipse.xtext.documentation.IEObjectDocumentationProvider;
import org.eclipse.xtext.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
@ -27,6 +35,9 @@ public class XtextDiagnosticConverter extends DiagnosticConverterImpl{
@Inject
private ILocationInFileProvider locationInFileProvider;
@Inject
private IEObjectDocumentationProvider documentationProvider;
@Override
protected IssueLocation getLocationData(EObject obj, EStructuralFeature structuralFeature, int index) {
if (NodeModelUtils.getNode(obj) == null) {
@ -44,4 +55,42 @@ public class XtextDiagnosticConverter extends DiagnosticConverterImpl{
return super.getLocationData(obj, structuralFeature, index);
}
@Override
protected Severity getSeverity(Diagnostic diagnostic) {
Severity result = super.getSeverity(diagnostic);
String issueCode = getIssueCode(diagnostic);
if (result == Severity.WARNING && issueCode != null) {
// only warnings can be suppressed
EObject causer = getCauser(diagnostic);
if (causer != null) {
if (isMarkedAsIgnored(causer, issueCode)) {
return null;
}
if (!(causer instanceof AbstractRule)) {
AbstractRule rule = GrammarUtil.containingRule(causer);
if (rule != null && isMarkedAsIgnored(rule, issueCode)) {
return null;
}
}
}
}
return result;
}
private final Pattern afterLastDot = Pattern.compile(".*\\W(\\w+)$");
protected boolean isMarkedAsIgnored(EObject object, String code) {
String documentation = documentationProvider.getDocumentation(object);
if (documentation != null) {
Matcher matcher = afterLastDot.matcher(code);
if (matcher.matches()) {
String suffix = matcher.group(1);
if (documentation.contains("Suppress[" + suffix + "]")) {
return true;
}
}
}
return false;
}
}

View file

@ -34,6 +34,13 @@ public class XtextRuleInspector<Result, RuleType extends AbstractRule> extends X
visitedRules = Sets.newHashSet();
}
/**
* @since 2.9
*/
protected String getIssueCode() {
return null;
}
public void inspect(RuleType rule) {
if (!canInspect(rule))
return;
@ -57,11 +64,11 @@ public class XtextRuleInspector<Result, RuleType extends AbstractRule> extends X
}
public void acceptError(String message, EObject object, EStructuralFeature feature) {
acceptor.acceptError(message, object, feature, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, null);
acceptor.acceptError(message, object, feature, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, getIssueCode());
}
public void acceptWarning(String message, EObject object, EStructuralFeature feature) {
acceptor.acceptWarning(message, object, feature, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, null);
acceptor.acceptWarning(message, object, feature, ValidationMessageAcceptor.INSIGNIFICANT_INDEX, getIssueCode());
}
public boolean addVisited(AbstractRule rule) {

View file

@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright (c) 2015 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.xtext.parser;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.AbstractElement;
import org.eclipse.xtext.XtextPackage;
import org.eclipse.xtext.conversion.ValueConverterException;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.parser.DefaultEcoreElementFactory;
/**
* The Xtext grammar allows to override the cardinality value by using patterns like
* {@code (feature+=RuleCall+)?}. Usually the '?' would override the '+' and the information
* about the '+' is completely lost. This factory will flag such patterns with a warning.
*
* @author Sebastian Zarnekow - Initial contribution and API
* @since 2.9
*/
public class CardinalityAwareEcoreFactory extends DefaultEcoreElementFactory {
@Override
public void set(EObject object, String feature, Object value, String ruleName, INode node) throws ValueConverterException {
if (object instanceof AbstractElement && XtextPackage.Literals.ABSTRACT_ELEMENT__CARDINALITY.getName().equals(feature)) {
AbstractElement casted = (AbstractElement) object;
String knownCardinality = casted.getCardinality();
if (knownCardinality != null) {
String newCardinality = String.valueOf(getTokenAsStringIfPossible(value));
if ("*".equals(newCardinality)) {
casted.setCardinality("*");
} else if ("*".equals(knownCardinality)) {
// nothing to do
} else if ("+".equals(knownCardinality)) {
if ("?".equals(newCardinality)) {
casted.setCardinality("*");
}
} else if ("?".equals(knownCardinality)) {
if ("+".equals(newCardinality)) {
casted.setCardinality("*");
}
}
throw new MoreThanOneCardinalityException(newCardinality, casted.getCardinality(), node);
}
}
super.set(object, feature, value, ruleName, node);
}
}

View file

@ -0,0 +1,31 @@
/*******************************************************************************
* Copyright (c) 2015 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.xtext.parser;
import org.eclipse.xtext.conversion.ValueConverterException;
import org.eclipse.xtext.nodemodel.SyntaxErrorMessage;
import org.eclipse.xtext.parser.antlr.SyntaxErrorMessageProvider;
/**
* @author Sebastian Zarnekow - Initial contribution and API
* @since 2.9
*/
public class CardinalityAwareSyntaxErrorMessageProvider extends SyntaxErrorMessageProvider {
public static final String CARDINALITY_ISSUE = "CardinalityAwareSyntaxErrorMessageProvider.overriddenCardinality";
@Override
public SyntaxErrorMessage getSyntaxErrorMessage(IValueConverterErrorContext context) {
ValueConverterException cause = context.getValueConverterException();
if (cause instanceof MoreThanOneCardinalityException) {
return new SyntaxErrorMessage(context.getDefaultMessage(), CARDINALITY_ISSUE);
}
return super.getSyntaxErrorMessage(context);
}
}

View file

@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright (c) 2015 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.xtext.parser;
import org.eclipse.xtext.conversion.ValueConverterException;
import org.eclipse.xtext.nodemodel.INode;
/**
* @author Sebastian Zarnekow - Initial contribution and API
* @since 2.9
*/
public class MoreThanOneCardinalityException extends ValueConverterException {
private static final long serialVersionUID = 1L;
public MoreThanOneCardinalityException(String newCardinality, String mergedCardinality, INode node) {
super(String.format("More than one cardinality was set. Merging '%s' with previously assigned cardinality to '%s'.", newCardinality, mergedCardinality),
node, null);
}
}

View file

@ -58,6 +58,7 @@ AbstractToken returns AbstractElement:
Action
;
/* Suppress[potentialOverride] */
AbstractTokenWithCardinality returns AbstractElement:
(Assignment |
AbstractTerminal) (cardinality=('?'|'*'|'+'))?
@ -129,6 +130,7 @@ TerminalGroup returns AbstractElement:
TerminalToken ({Group.tokens+=current} (tokens+=TerminalToken)+)?
;
/* Suppress[potentialOverride] */
TerminalToken returns AbstractElement:
TerminalTokenElement (cardinality=('?'|'*'|'+'))?
;

View file

@ -8,6 +8,7 @@
*******************************************************************************/
grammar org.eclipse.xtext.enumrules.EnumRulesTestLanguage with org.eclipse.xtext.common.Terminals
/* Suppress[external] */
import "classpath:/org/eclipse/xtext/enumrules/enums.ecore"
generate enumRulesTestLanguage "http://www.eclipse.org/2009/tmf/xtext/EnumRulesTest"

View file

@ -1,5 +1,6 @@
grammar org.eclipse.xtext.generator.ecore.EcoreFragmentTestLanguage with org.eclipse.xtext.common.Terminals
/* Suppress[external] */
import "classpath:/org/eclipse/xtext/generator/ecore/First.ecore" as first
generate second "http://www.eclipse.org/2009/tmf/xtext/EcoreFragmentTestLanguage" as second

View file

@ -14,9 +14,11 @@ AType:
AnotherType:
'bar' {AnotherType};
/* Suppress[noInstantiation] */
FinderKeywords:
'myKeyword' name=ID? 'myKeyword' 'lala';
/* Suppress[potentialOverride] */
FinderKeywordPairs:
'begin' 'whatever' name=ID ('begin' nested=ID 'end')* 'end' 'begin' second=ID 'end';

View file

@ -1,6 +1,8 @@
grammar org.eclipse.xtext.generator.grammarAccess.GrammarAccessTestLanguage with org.eclipse.xtext.common.Terminals
/* Suppress[external] */
import "classpath:/org/eclipse/xtext/generator/grammarAccess/ametamodel.ecore#//asubpackage" as root
/* Suppress[external] */
import "classpath:/org/eclipse/xtext/generator/grammarAccess/ametamodel.ecore#//asubpackage/emptyPackage/subsubpackage" as sub
Root returns root::AModel:

View file

@ -14,6 +14,7 @@ import "http://www.eclipse.org/emf/2002/Ecore" as ecore
InheritedParserRule returns mm::AType:
'element' name=ID;
/* Suppress[noInstantiation] */
AbstractCallOverridenParserRule returns mm::AModel:
'overridemodel' (elements+=OverridableParserRule)*;
@ -23,6 +24,7 @@ OverridableParserRule returns mm::AType :
OverridableParserRule2 returns mm::AType :
'other element' name=STRING;
/* Suppress[noInstantiation] */
AbstractCallExtendedParserRule returns mm::AModel:
'extendedmodel' (elements+=ExtendableParserRule)*;

View file

@ -9,6 +9,7 @@ grammar org.eclipse.xtext.linking.Bug287988TestLanguage with org.eclipse.xtext.c
generate bug287988Test "http://eclipse.org/xtext/Bug287988TestLanguage"
/* Suppress[noInstantiation] */
Model:
('actions' attributes+=BaseAttribute*)
| ('simple' attributes+=SimpleAttribute*)

View file

@ -12,6 +12,10 @@ generate lazyLinking "http://eclipse.org/xtext/lazyLinkingTestLanguage"
Model :
types+=Type*;
/*
* Suppress[BidirectionalReference]
* Suppress[potentialOverride]
*/
Type :
'type' name=ID ('extends' ^extends=[Type] '.' parentId=[Property])? ('for' parentId=[Property] 'in' ^extends=[Type])? '{'
(properties+=Property)*

View file

@ -8,7 +8,8 @@
*******************************************************************************/
grammar org.eclipse.xtext.metamodelreferencing.tests.EcoreReferenceTestLanguage with org.eclipse.xtext.common.Terminals
import "http://www.eclipse.org/2011/tmf/xtext/ecorePerNsURI" // the warning is intentional
/* Suppress[external] */
import "http://www.eclipse.org/2011/tmf/xtext/ecorePerNsURI"
import "http://www.eclipse.org/2011/tmf/xtext/ecorePerPlatformPlugin"
import "http://www.eclipse.org/2011/tmf/xtext/ecorePerPlatformResource"
import "http://www.eclipse.org/emf/2002/Ecore"

View file

@ -9,6 +9,7 @@ grammar org.eclipse.xtext.parser.antlr.Bug296889ExTestLanguage with org.eclipse.
generate bug296889ExTest "http://eclipse.org/xtext/Bug296889ExTestLanguage"
/* Suppress[noInstantiation] */
Model: "Model" expressions += Expression* | "DataType" values += DataTypeExpression* ;
Expression: Postop | Preop ;

View file

@ -9,6 +9,7 @@ grammar org.eclipse.xtext.parser.antlr.Bug296889TestLanguage with org.eclipse.xt
generate bug296889Test "http://eclipse.org/xtext/Bug296889TestLanguage"
/* Suppress[noInstantiation] */
Model: "Model" expressions += Expression* | "DataType" values += DataTypeExpression* ;
Expression: Postop | Preop ;

View file

@ -57,6 +57,7 @@ AbstractToken returns AbstractElement:
Action
;
/* Suppress[potentialOverride] */
AbstractTokenWithCardinality returns AbstractElement:
(Assignment |
AbstractTerminal) (cardinality=('?'|'*'|'+'))?
@ -120,6 +121,7 @@ TerminalGroup returns AbstractElement:
TerminalToken ({Group.tokens+=current} (tokens+=TerminalToken)+)?
;
/* Suppress[potentialOverride] */
TerminalToken returns AbstractElement:
TerminalTokenElement (cardinality=('?'|'*'|'+'))?
;

View file

@ -54,6 +54,7 @@ UnorderedDatatype:
| '14' (('a' & 'b') & ('c' & 'd'))+
;
/* Suppress[potentialOverride] */
UnorderedSerialization: {UnorderedSerialization} (
'1' first?='a'? & second?='b'? & third?='c'? & forth?='d'?
| '2' (firstAsList+='a' & secondAsList+='b')*

View file

@ -15,9 +15,11 @@ import "http://www.eclipse.org/2008/Xtext" as xtext
Root:
"test" (TestLinewrap | TestIndentation);
/* Suppress[noInstantiation] */
TestLinewrap:
"linewrap" items+=STRING*;
/* Suppress[noInstantiation] */
TestIndentation:
"indentation" "{"
(sub+=TestIndentation |

View file

@ -16,10 +16,12 @@ import "http://www.eclipse.org/2008/Xtext" as xtext
Root:
"test" (TestLinewrap | TestIndentation);
/* Suppress[noInstantiation] */
TestLinewrap:
"linewrap" items+=STRING*;
/* Suppress[noInstantiation] */
TestIndentation:
"indentation" "{"
(sub+=TestIndentation |

View file

@ -21,6 +21,7 @@ Term returns Expression:
Atom:
name=ID;
/* Suppress[potentialOverride] */
Parens returns Expression:
'(' Op ')' em='!'?;
@ -33,19 +34,23 @@ StrangeStuff :
//TrickyA returns TypeA1: 'TA' TrickyA1 (name += ID)* ({TypeB.x=current} 'x' | {TypeC.x=current} 'y')? name+=STRING;
//TrickyA1 returns TypeD: name+=ID;
/* Suppress[noInstantiation] */
TrickyB : 'TB' (name = ID type += INT)? (type += INT)*;
TrickyC : 'TC' name = ID ({C1.x=current} 'x')? ({C2.y=current} 'y')? ({C3.z=current} 'z')?;
/* Suppress[noInstantiation] */
TrickyD: 'TD' (name += INT foo = STRING type += ID)? (name += INT type += ID)? (type += ID)*;
// 34 "abc" XX 123 "de" YY x 34 DD 45 CC
/* Suppress[noInstantiation] */
TrickyE: 'TE' (name+=INT foo+=STRING type+=ID)* 'x' (name+=INT type+=ID)*;
//
TrickyF: 'TF' (name+=ID type+=INT)* (name+=ID | type+=INT);
TrickyG: 'TG' tree=TrickyG1;
TrickyG: 'TG' tree=TrickyG1;
/* Suppress[noInstantiation] */
TrickyG1: '[' (vals+=TrickyG2 (',' vals+=TrickyG2)*)? ']';
TrickyG2: TrickyG1 | val=INT;

View file

@ -23,15 +23,18 @@ EnumBug:
enum EnumBugEnum: array="array" | object="object" | resultSet="resultSet" | iterator="iterator";
/* Suppress[noInstantiation] */
Commentable:
'#3' item+=CommentableItem*;
CommentableItem:
'item' id=ID;
/* Suppress[noInstantiation] */
ValueList:
'#4' ids+=FQN*;
/* Suppress[noInstantiation] */
RefList:
'#5' objs+=RefObj* 'refs' refs+=[RefObj|FQN]*;
@ -42,6 +45,7 @@ SingleRef:
'#6' obj=RefObj 'ref' ref=[RefObj|FQN];
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=297938
/* Suppress[noInstantiation] */
AppendToFileEnd:
'#7' items+=AppendToFileEndItem*;

View file

@ -25,5 +25,6 @@ TwoRequired:
TwoOptions:
"twooptions" ("one" one=ID | "two" two=ID);
/* Suppress[noInstantiation] */
Indent:
"{" req=TwoRequired? opt=TwoOptions? indent+=Indent* "}";

View file

@ -24,6 +24,7 @@ Term returns Expression:
Atom:
name=ID;
/* Suppress[potentialOverride] */
Parens returns Expression:
'(' Op ')' em='!'?;
@ -68,13 +69,15 @@ Loop4:
LoopBug285452:
'#12' (interface?="interface"|"class") name=ID;
/* Suppress[potentialOverride] */
DuplicateBug284491:
'#13' (static?='static' | final?='final' | transient?='transient')*;
EmptyObjectBug284850:
'#14' items=EmptyObjectItems;
/* Suppress[noInstantiation] */
EmptyObjectItems:
list+=EmptyObjectItem*;
@ -112,9 +115,11 @@ TypeBug2B: {TypeBug2B} "kb" name=ID;
Bug305171:
"#19" (('kx' x+=ID (',' x+=ID)*)? (('ky' y+=ID (',' y+=ID)*)? ('kz' z+=ID (',' z+=ID)*)?)) name=ID;
/* Suppress[noInstantiation] */
Bug310435Enum:
"#20" ('kw1' lits+=EnumBug310435Lit1 | 'kw2' lits+=EnumBug310435Lit2)*;
/* Suppress[noInstantiation] */
Bug310435Val:
"#21" ('kw1' lits+=ID | 'kw2' lits+=STRING)*;
@ -124,6 +129,7 @@ enum EnumBug310435Lit1 returns EnumBug310435Enum:
enum EnumBug310435Lit2 returns EnumBug310435Enum:
lit2='lit2';
/* Suppress[noInstantiation] */
CrossRefNameTest:
"#22" named+=CrossRefNamed* "kw1" ("kw2" ref+=[CrossRefNamed|ID1] | "kw3" ref+=[CrossRefNamed|ID2])*;

View file

@ -14,6 +14,7 @@ Model:
domainModel = DomainModel
;
/* Suppress[noInstantiation] */
DomainModel:
'entities'
(entities+=Entity)*

View file

@ -10,6 +10,7 @@ grammar org.eclipse.xtext.testlanguages.FowlerDslTestLanguage with org.eclipse.x
generate fowlerdsl "http://example.xtext.org/FowlerDslTestLanguage"
/* Suppress[noInstantiation] */
Statemachine :
'events'
(events+=Event)*

View file

@ -65,6 +65,7 @@ Combination1:
Combination2:
"#14" val1=ID (("kw1" val2=ID) | (val3+=ID val4+=ID)*);
/* Suppress[potentialOverride] */
Combination3:
"#15" (val1=ID | val2=INT | val3=STRING)*;
@ -74,6 +75,7 @@ Combination4:
List1:
"#17" val1+=ID ("," val1+=ID)*;
/* Suppress[noInstantiation] */
List2:
"#18" (val1+=ID ("," val1+=ID)*)?;
@ -91,19 +93,22 @@ AltList1:
AltList2:
"#23" (val1+=ID val2=ID | "kw" val1+=ID ("," val1+=ID)* val3=ID);
/* Suppress[noInstantiation] */
TransientObject:
"#24" (val1=ID nested=TransientObjectSub)?;
TransientObjectSub:
val2=ID val3=ID;
/* Suppress[noInstantiation] */
TransientSerializeables1:
"#25" (val1=ID enum1=TransientSerializeables1Enum)? (val2=ID int1=INT)?;
enum TransientSerializeables1Enum:
lit1 | lit2;
/* Suppress[potentialOverride] */
StaticSimplification:
"#26" ("kw1"|{EmptyAlternativeSub}|val1=ID) ("kw2"|val2=ID) ("kw3" ("kw4" (val3=ID)+)?);
@ -117,6 +122,7 @@ TwoVersionNo2 returns TwoVersion:
shared1=ID? shared2=ID "long" (shared3+=ID shared3+=ID*)?
"extra" extra1=ID? ((extra2=ID extra3=ID) | "two" extra4=ID)?;
/* Suppress[noInstantiation] */
Heuristic1:
"#28" ("kw1" a+=ID b+=ID)* ("kw2" a+=ID c+=ID)* ("kw3" b+=ID c+=ID)*;

View file

@ -0,0 +1,50 @@
/*******************************************************************************
* Copyright (c) 2015 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.xtext;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.xtext.Grammar;
import org.eclipse.xtext.ParserRule;
import org.eclipse.xtext.XtextStandaloneSetup;
import org.eclipse.xtext.validation.AbstractValidationMessageAcceptingTestCase;
import org.junit.Test;
/**
* @author Sebastian Zarnekow - Initial contribution and API
*/
public class Bug287082Test extends AbstractValidationMessageAcceptingTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
with(XtextStandaloneSetup.class);
}
@Test public void testBug285605() throws Exception {
String grammarAsString = "grammar org.xtext.example.MyDsl with org.eclipse.xtext.common.Terminals\n" +
"generate myDsl \"http://www.xtext.org/example/MyDsl\"\n" +
"\n" +
"A: {A} (feature=ID+)?;\n";
Grammar grammar = (Grammar) getModel(grammarAsString);
OverriddenValueInspector inspector = new OverriddenValueInspector(this);
inspector.inspect((ParserRule) grammar.getRules().get(0));
}
@Override
public void acceptWarning(String message, EObject object, EStructuralFeature feature, int index, String code,
String... issueData) {
if (code.equals(OverriddenValueInspector.ISSUE_CODE)) {
String expectation = "";
assertEquals(expectation, message);
} else {
super.acceptWarning(message, object, feature, index, code, issueData);
}
}
}

View file

@ -42,6 +42,14 @@ public class XtextGrammarSerializationTest extends AbstractXtextTests {
+ "mm \"http://bar\" as fooMM\n\nStartRule returns fooMM::T:\n name=ID;";
doTestSerialization(model, expectedModel);
}
@Test public void testSerializationWithCardinalityOverride() throws Exception {
final String model = "grammar foo with org.eclipse.xtext.common.Terminals\n"
+ "generate mm \"http://bar\" as fooMM\n" + "StartRule returns fooMM::T: (name+=ID?)+;";
final String expectedModel = "grammar foo with org.eclipse.xtext.common.Terminals\n\ngenerate "
+ "mm \"http://bar\" as fooMM\n\nStartRule returns fooMM::T:\n name+=ID*;";
doTestSerialization(model, expectedModel);
}
private void doTestSerialization(String model, String expectedModel) throws Exception {
final XtextResource resource = getResourceFromString(model);

View file

@ -12,6 +12,7 @@ import static com.google.common.collect.Maps.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.common.util.Diagnostic;
@ -44,10 +45,14 @@ import org.eclipse.xtext.UnorderedGroup;
import org.eclipse.xtext.XtextFactory;
import org.eclipse.xtext.XtextStandaloneSetup;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.util.CancelIndicator;
import org.eclipse.xtext.util.StringInputStream;
import org.eclipse.xtext.validation.AbstractDeclarativeValidator.State;
import org.eclipse.xtext.validation.AbstractValidationMessageAcceptingTestCase;
import org.eclipse.xtext.validation.AbstractValidationMessageAcceptor;
import org.eclipse.xtext.validation.CheckMode;
import org.eclipse.xtext.validation.IResourceValidator;
import org.eclipse.xtext.validation.Issue;
import org.eclipse.xtext.validation.ValidationMessageAcceptor;
import org.junit.Ignore;
import org.junit.Test;
@ -77,6 +82,55 @@ public class XtextValidationTest extends AbstractValidationMessageAcceptingTestC
state.context = newHashMap();
}
/**
* see https://bugs.eclipse.org/bugs/show_bug.cgi?id=287082
*/
@Test public void testOverriddenCardinality() throws Exception {
XtextResource resource = getResourceFromString(
"grammar Bar with org.eclipse.xtext.common.Terminals\n" +
"generate metamodel 'myURI'\n" +
"Model: ((name+=ID+)+)?;\n");
assertTrue(resource.getErrors().toString(), resource.getErrors().isEmpty());
assertEquals(2, resource.getWarnings().size());
String message = resource.getWarnings().get(0).getMessage();
assertEquals("More than one cardinality was set. Merging '+' with previously assigned cardinality to '+'.", message);
message = resource.getWarnings().get(1).getMessage();
assertEquals("More than one cardinality was set. Merging '?' with previously assigned cardinality to '*'.", message);
}
@Test public void testSupressedWarning_01() throws Exception {
XtextResource resource = getResourceFromString(
"grammar org.acme.Bar with org.eclipse.xtext.common.Terminals\n" +
"generate metamodel 'myURI'\n" +
"Model: child=Child;\n" +
"/* Suppress[noInstantiation] */\n" +
"Child: name=ID?;");
assertTrue(resource.getErrors().toString(), resource.getErrors().isEmpty());
assertTrue(resource.getWarnings().toString(), resource.getWarnings().isEmpty());
IResourceValidator validator = get(IResourceValidator.class);
List<Issue> issues = validator.validate(resource, CheckMode.FAST_ONLY, CancelIndicator.NullImpl);
assertTrue(issues.toString(), issues.isEmpty());
}
@Test public void testSupressedWarning_02() throws Exception {
XtextResource resource = getResourceFromString(
"grammar org.acme.Bar with org.eclipse.xtext.common.Terminals\n" +
"generate metamodel 'myURI'\n" +
"/* Suppress[potentialOverride] */\n" +
"Parens: \n" +
" ('(' Parens ')'|name=ID) em='!'?;");
assertTrue(resource.getErrors().toString(), resource.getErrors().isEmpty());
assertTrue(resource.getWarnings().toString(), resource.getWarnings().isEmpty());
IResourceValidator validator = get(IResourceValidator.class);
List<Issue> issues = validator.validate(resource, CheckMode.FAST_ONLY, CancelIndicator.NullImpl);
assertTrue(issues.toString(), issues.isEmpty());
}
/**
* see https://bugs.eclipse.org/bugs/show_bug.cgi?id=348052
*/

View file

@ -9,6 +9,7 @@ grammar org.eclipse.xtext.xtext.ecoreInference.DataTypeRuleWithEnumResultTestLan
with org.eclipse.xtext.enumrules.EnumRulesTestLanguage
import 'http://www.eclipse.org/2009/tmf/xtext/EnumRulesTest'
/* Suppress[external] */
import 'classpath:/org/eclipse/xtext/enumrules/enums.ecore'
Model:

View file

@ -1,5 +1,6 @@
grammar org.eclipse.xtext.xtext.ecoreInference.Test with org.eclipse.xtext.common.Terminals
generate root "http://root"
/* Suppress[external] */
import "classpath:/org/eclipse/xtext/xtext/ecoreInference/test.ecore" as test
Root :