Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: a8bf34bd3425a9bef710fe4794dfc518c5aa70e0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
/*******************************************************************************
 * Copyright (c) 2013 protos software gmbh (http://www.protos.de).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 * 
 * CONTRIBUTORS:
 * 		Eyrak Paen (initial contribution)
 * 
 *******************************************************************************/

package org.eclipse.etrice.core.common.validation;

import java.util.HashSet;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.etrice.core.common.base.Annotation;
import org.eclipse.etrice.core.common.base.AnnotationAttribute;
import org.eclipse.etrice.core.common.base.AnnotationType;
import org.eclipse.etrice.core.common.base.BasePackage;
import org.eclipse.etrice.core.common.base.BooleanLiteral;
import org.eclipse.etrice.core.common.base.Documentation;
import org.eclipse.etrice.core.common.base.EnumAnnotationAttribute;
import org.eclipse.etrice.core.common.base.Import;
import org.eclipse.etrice.core.common.base.IntLiteral;
import org.eclipse.etrice.core.common.base.KeyValue;
import org.eclipse.etrice.core.common.base.RealLiteral;
import org.eclipse.etrice.core.common.base.SimpleAnnotationAttribute;
import org.eclipse.etrice.core.common.base.StringLiteral;
import org.eclipse.etrice.core.common.base.util.ImportHelpers;
import org.eclipse.etrice.generator.base.io.IModelPathProvider;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.scoping.impl.ImportUriResolver;
import org.eclipse.xtext.validation.Check;

import com.google.inject.Inject;

/**
 * Custom validation rules. 
 *
 * see http://www.eclipse.org/Xtext/documentation.html#validation
 */
public class BaseJavaValidator extends org.eclipse.etrice.core.common.validation.AbstractBaseJavaValidator {
	
	public static final String MANDATORY_ATTRIBUTE_MISSING = "BaseJavaValidator.MandatoryAttributeMissing";
	public static final String DUPLICATE_ANNOTATION_TARGETS = "BaseJavaValidator.DuplicateAnnotationTargets";
	public static final String UNDEFINED_ANNOTATION_ATTRIBUTE = "BaseJavaValidator.UndfinedAnnotationAttribute";
	public static final String UNDEFINED_ANNOTATION_ATTRIBUTE_VALUE = "BaseJavaValidator.UndfinedAnnotationAttributeValue";
	public static final String DUPLICATE_ANNOTATION_ATTRIBUTE = "BaseJavaValidator.DuplicateAnnotationAttribute";
	public static final String DEPRECATED_IMPORT_URI = "BaseJavaValidator.DeprecatedImportUri";
	public static final String MODELPATH_DESCRIPTION_MISSING = "BaseJavaValidator.ModelpathDescriptionMissing";
	public static final String IMPORTED_NAMESPACE_MISSING = "BaseJavaValidator.ImportedNamespaceMissing";
	
	@Inject ImportUriResolver importUriResolver;
	@Inject ImportHelpers importHelpers;
	@Inject IModelPathProvider modelPathProvider;
	
	@Check
	public void checkDocumentation(Documentation doc) {
		if (doc.getLines().isEmpty())
			error("documentation must not be empty", doc, BasePackage.Literals.DOCUMENTATION__LINES);
	}
	
	@Check
	public void checkAnnotationTypeTargetsUnique(AnnotationType at) {
		HashSet<String> targets = new HashSet<String>();
		for (String tgt : at.getTargets()) {
			if (!targets.add(tgt)) {
				error("The target "+tgt+" is defined more than once",
						at,
						BasePackage.Literals.ANNOTATION_TYPE__TARGETS,
						DUPLICATE_ANNOTATION_TARGETS,
						tgt);
			}
		}
	}
	
	@Check
	public void checkAnnotationAttributeMandatory(Annotation a) {
		if(a.getType().eIsProxy()) return;
		
		for (AnnotationAttribute att : a.getType().getAttributes()) {
			if (!att.isOptional()) {
				boolean isDefined = false;
				for (KeyValue kv : a.getAttributes()) {
					if (kv.getKey().equals(att.getName())) {
						isDefined = true;
						break;
					}
				}
				if (!isDefined) {
					error("Mandatory attribute "+att.getName()+" is missing",
							a,
							BasePackage.Literals.ANNOTATION__ATTRIBUTES,
							MANDATORY_ATTRIBUTE_MISSING,
							att.getName());
				}
			}
		}
	}
	
	@Check
	public void checkAnnotationAttributeType(Annotation a) {
		if(a.getType().eIsProxy()) return;
		
		HashSet<String> names = new HashSet<String>();
		for (KeyValue kv : a.getAttributes()) {
			int idx = a.getAttributes().indexOf(kv);
			
			if (!names.add(kv.getKey())) {
				error("duplicate attribute "+kv.getKey(),
						a,
						BasePackage.Literals.ANNOTATION__ATTRIBUTES,
						idx,
						DUPLICATE_ANNOTATION_ATTRIBUTE,
						kv.getKey()
					);
			}
			boolean isAllowed = false;
			for (AnnotationAttribute att : a.getType().getAttributes()) {
				if (att.getName().equals(kv.getKey())) {
					isAllowed = true;
					
					// check also value of enum attribute
					if (kv.getValue()!=null) {
						if (att instanceof EnumAnnotationAttribute) {
							EList<String> values = ((EnumAnnotationAttribute) att).getValues();
							if (kv.getValue() instanceof StringLiteral) {
								boolean valueAllowed = false;
								String value = ((StringLiteral)kv.getValue()).getValue();
								for (String val : values) {
									if (val.equals(value)) {
										valueAllowed = true;
										break;
									}
								}
								if (!valueAllowed) {
									error("Choose one of the allowed enum values",
											kv,
											BasePackage.Literals.KEY_VALUE__VALUE,
											UNDEFINED_ANNOTATION_ATTRIBUTE_VALUE,
											values.toArray(new String[values.size()]));
								}
							}
							else {
								error("Choose one of the allowed enum values (values has to be a string)",
										kv,
										BasePackage.Literals.KEY_VALUE__VALUE,
										UNDEFINED_ANNOTATION_ATTRIBUTE_VALUE,
										values.toArray(new String[values.size()]));
							}
						}
						else if (att instanceof SimpleAnnotationAttribute) {
							switch (((SimpleAnnotationAttribute) att).getType()) {
							case BOOL :
								if (!(kv.getValue() instanceof BooleanLiteral))
									error("boolean literal expected", kv, BasePackage.Literals.KEY_VALUE__VALUE);
								break;
							case CHAR :
								if (!(kv.getValue() instanceof StringLiteral))
									error("char/string literal expected", kv, BasePackage.Literals.KEY_VALUE__VALUE);
								break;
							case INT :
								if (!(kv.getValue() instanceof IntLiteral))
									error("integer literal expected", kv, BasePackage.Literals.KEY_VALUE__VALUE);
								break;
							case REAL :
								if (!(kv.getValue() instanceof RealLiteral))
									error("real literal expected", kv, BasePackage.Literals.KEY_VALUE__VALUE);
								break;
							default :
								break;
							}
						}
					}
					break;
				}
			}
			if (!isAllowed) {
				error("Attribute "+kv.getKey()+" is undefined",
						a,
						BasePackage.Literals.ANNOTATION__ATTRIBUTES,
						idx,
						UNDEFINED_ANNOTATION_ATTRIBUTE,
						kv.getKey());
			}
		}
	}

	@Check
	public void checkImportedURI(Import imp) {
		if(imp.getImportURI() == null) {
			return;
		}
		
		Resource resource = imp.eResource();
		if(!modelPathProvider.get(resource).isEmpty()) {
			warning("import statements using uris are deprecated", BasePackage.Literals.IMPORT__IMPORT_URI, DEPRECATED_IMPORT_URI);
		}
		
		String uriString = importUriResolver.resolve(imp);
		if (uriString == null) {
			warning("could not load referenced model", BasePackage.Literals.IMPORT__IMPORT_URI);
			return;
		}

		URI uri = URI.createURI(uriString);
				
		if(resource.getResourceSet() instanceof ResourceSetImpl) {
			ResourceSetImpl rs = (ResourceSetImpl) resource.getResourceSet();
			if(rs.getURIResourceMap().containsKey(uri)) {
				return;
			}
		}

		try {			
			Resource importedResource = new ResourceSetImpl().getResource(uri, true);
			if (importedResource == null)
				return;

			if (importedResource.getContents().isEmpty()) {
				// importedResource is empty after being loaded the first time (<=> RuntimeException below)
				warning("could not load referenced model", BasePackage.Literals.IMPORT__IMPORT_URI);
				return;
			}
		} catch (RuntimeException re) {
			warning("could not load referenced model", BasePackage.Literals.IMPORT__IMPORT_URI);
			return;
		}
	}
	
	/**
	 * Check that the imported namespace can be found by the global scope provider.
	 * 
	 * @param imp the import to check
	 */
	@Check
	public void checkImportedNamespace(Import imp) {
		if(imp.getImportURI() != null || imp.getImportedNamespace() == null) {
			return;
		}
		
		QualifiedName fqn = importHelpers.toFQN(imp);
		
		Resource resource = imp.eResource();
		if(modelPathProvider.get(resource).isEmpty()) {
			error("no modelpath definition present", BasePackage.Literals.IMPORT__IMPORTED_NAMESPACE, MODELPATH_DESCRIPTION_MISSING);
			return;
		}	
		IEObjectDescription eod = importHelpers.getVisibleScope(resource).getSingleElement(fqn);
		if(eod == null) {
			error("could not find imported namespace " + fqn, BasePackage.Literals.IMPORT__IMPORTED_NAMESPACE, IMPORTED_NAMESPACE_MISSING);
		}
	}
}

Back to the top