Commit 8978f51a authored by Daniel Honsel's avatar Daniel Honsel
Browse files

added support for statistics and more validation rules

parent a2956934
Loading
Loading
Loading
Loading
+185 −0
Original line number Diff line number Diff line
package de.ugoe.cs.swe.validation;

import java.util.List;
import java.util.Map;

import org.eclipse.emf.common.util.URI;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import de.ugoe.cs.swe.common.MiscTools;
import de.ugoe.cs.swe.common.logging.LoggingInterface;
import de.ugoe.cs.swe.common.logging.LoggingInterface.MessageClass;
import de.ugoe.cs.swe.tTCN3.TTCN3Module;

public class TTCN3StatisticsProvider {
	private Map<String, TTCN3Module> modules = Maps.newHashMap();
	private Map<String, List<String>> imports = Maps.newHashMap();
	private Map<String, List<String>> importedModules = Maps.newHashMap();
	
	private int parsedLines;
	private int countUniversal;
	private int countGeneral;
	private int countNaming;
	private int countDocumentation;
	private int countLog;
	private int countStructure;
	private int countStyle;
	private int countModularization;
	
	public int getCountNaming() {
		return countNaming;
	}

	public void increaseCountNaming() {
		this.countNaming++;
	}

	public int getCountUniversal() {
		return countUniversal;
	}

	public void incrementCountUniversal() {
		this.countUniversal++;
	}

	public int getCountGeneral() {
		return countGeneral;
	}

	public void incrementCountGeneral() {
		this.countGeneral++;
	}

	public int getCountDocumentation() {
		return countDocumentation;
	}

	public void incrementCountDocumentation() {
		this.countDocumentation++;
	}

	public int getCountLog() {
		return countLog;
	}

	public void incrementCountLog() {
		this.countLog++;
	}

	public int getCountStructure() {
		return countStructure;
	}

	public void incrementCountStructure() {
		this.countStructure++;
	}

	public int getCountStyle() {
		return countStyle;
	}

	public void incrementCountStyle() {
		this.countStyle++;
	}

	public int getCountModularization() {
		return countModularization;
	}

	public void incrementCountModularization() {
		this.countModularization++;
	}

	public int getParsedLines() {
		return parsedLines;
	}

	private static TTCN3StatisticsProvider instance = new TTCN3StatisticsProvider();

	private TTCN3StatisticsProvider() {
	}

	public static TTCN3StatisticsProvider getInstance() {
		return instance;
	}

	public void addModule(TTCN3Module module) {
		modules.put(module.getName(), module);
	}

	public void addImport(String module, String importedModule) {
		if (imports.containsKey(module)) {
			imports.get(module).add(importedModule);
		} else {
			List<String> importedModules = Lists.newArrayList();
			importedModules.add(importedModule);
			imports.put(module, importedModules);
		}
		if (importedModules.containsKey(importedModule)) {
			importedModules.get(importedModule).add(module);
		} else {
			List<String> modules = Lists.newArrayList();
			modules.add(module);
			importedModules.put(importedModule, modules);
		}
	}

	public void printListImportedModuleNames(boolean fileNames, LoggingInterface logger) {
		printImportModuleNames(fileNames, logger, imports, true);
	}

	public void printListImportingModuleNames(boolean fileNames, LoggingInterface logger) {
		printImportModuleNames(fileNames, logger, importedModules, false);
	}

	private void printImportModuleNames(boolean fileNames, LoggingInterface logger, Map<String, List<String>> map, boolean importing) {
		for (String moduleName : map.keySet()) {
			TTCN3Module module = modules.get(moduleName);
			if (module != null) {
				INode node = NodeModelUtils.getNode(module);
				String importList = "";
				int index = 0;
				int size = map.get(moduleName).size();
				for (String importName : map.get(moduleName)) {
					index++;
					TTCN3Module importModule = modules.get(importName);
					if (importModule != null) {
						if (fileNames) {
							importList += importName + " located in " + importModule.eResource().getURI().devicePath()
									+ (index < size ? ", " : "");
						} else {
							importList += importName + (index < size ? ", " : "");
						}
					} else {
						if (importing) {
							importList += "(<" + importName + "> is unresolved!)" + (index < size ? ", " : "");
							printModuleNotResolvedMessage(module.eResource().getURI(), node, importName, logger);
						}
					}
				}
				String message = "";
				if (importing) {
					message = "Importing from module(s) \"" + importList + "\"";
				} else {
					message = "Module \"" + module.getName() + "\" is imported in module(s) \"" + importList + "\"";
				}
				logger.logInformation(module.eResource().getURI(), node.getStartLine(), node.getEndLine(), MessageClass.GENERAL,
						message, "1.18, " + MiscTools.getMethodName());
			}
		}
	}

	private void printModuleNotResolvedMessage(URI uri, INode node, String name, LoggingInterface logger) {
		logger.logInformation(uri, node.getStartLine(), node.getEndLine(), MessageClass.GENERAL, "Imported module \"" + name
				+ "\" cannot be resolved!", "1.18, " + MiscTools.getMethodName());
	}
	
	public void addParedLines(int lines) {
		parsedLines += lines;
	}
	
}
+68 −4
Original line number Diff line number Diff line
@@ -150,9 +150,8 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		} else {
			message = " Local Constant"
			regExp = activeProfile.namingConventionsConfig.localConstantRegExp

			const.checkIdentifierForNamingConventionCompliance(regExp, message)
		}
		const.checkIdentifierForNamingConventionCompliance(regExp, message)
	}

	//TODO: fix external constants
@@ -376,6 +375,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		val INode node = NodeModelUtils.getNode(object)

		if (!regExp.regExpMatch(object.name)) {
			TTCN3StatisticsProvider.getInstance.increaseCountNaming
			val message = "\"" + object.name + "\" does not comply to the naming conventions for \"" + type + "\"!"
			info(
				message,
@@ -450,6 +450,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {

		val INode node = NodeModelUtils.getNode(group)
		if (current.compareToIgnoreCase(previous) <= 0) {
			TTCN3StatisticsProvider.getInstance.incrementCountStructure
			val message = "Type definitions <\"" + previous + "\",\"" + current + "\"> within group \"" + group.name +
				"\" are not alphabetically ordered!"

@@ -474,6 +475,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		var message = "";

		if (parentGroup == null) {
			TTCN3StatisticsProvider.getInstance.incrementCountStructure
			message = "Port type definition for \"" + port.name +
				"\" is found outside a group definition! Related messages can therefore never be in the same group as the port definition!"
			warning(
@@ -513,6 +515,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		val GroupDef parentGroupType = type.findDesiredParent(GroupDef)

		if (parentGroupType == null) {
			TTCN3StatisticsProvider.getInstance.incrementCountStructure
			val message = "" + typeName + " definition for \"" + type.name + "\" <" + nodeType.startLine + "," +
				parentModuleType.name + ",- " + "> " + "related to port type definition for \"" + port.name + "\" <" +
				nodePort.startLine + "," + parentModulePort.name + "," + parentGroupPort.name + "> " +
@@ -530,6 +533,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		}

		if (parentModulePort != parentModuleType) {
			TTCN3StatisticsProvider.getInstance.incrementCountStructure
			val message = "" + typeName + " definition for \"" + type.name + "\" <" + nodeType.startLine + "," +
				parentModuleType.name + "," + parentGroupType.name + "> " + "related to port type definition for \"" +
				port.name + "\" <" + nodePort.startLine + "," + parentModulePort.name + "," + parentGroupPort.name +
@@ -550,6 +554,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {

			// check nested subgroups
			if (parentGroupPort.getAllContentsOfType(GroupDef).contains(parentGroupType)) {
				TTCN3StatisticsProvider.getInstance.incrementCountStructure
				val message = "" + typeName + " definition for \"" + type.name + "\" <" + nodeType.startLine + "," +
					parentModuleType.name + "," + parentGroupType.name + "> " + "related to port type definition for \"" +
					port.name + "\" <" + nodePort.startLine + "," + parentModulePort.name + "," + parentGroupPort.name +
@@ -565,6 +570,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
				);
				return;
			} else {
				TTCN3StatisticsProvider.getInstance.incrementCountStructure
				val message = "" + typeName + " definition for \"" + type.name + "\" <" + nodeType.startLine + "," +
					parentModuleType.name + "," + parentGroupType.name + "> " + "related to port type definition for \"" +
					port.name + "\" <" + nodePort.startLine + "," + parentModulePort.name + "," + parentGroupPort.name +
@@ -613,6 +619,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		}

		if (allIsUsed) {
			TTCN3StatisticsProvider.getInstance.incrementCountStructure
			val message = "\"all\" keyword is used in the definition of port \"" + port.name + "\"!"
			warning(
				message,
@@ -652,6 +659,9 @@ class TTCN3Validator extends AbstractTTCN3Validator {
			GotoStatement: message = "A \"goto\" statement is used!"
			LabelStatement: message = "A \"label\" statement is used!"
		}
		
		TTCN3StatisticsProvider.getInstance.incrementCountStyle
		
		warning(
			message,
			TTCN3Package.eINSTANCE.TTCN3Reference_Name,
@@ -670,6 +680,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		val depth = alt.nestingDepth(AltConstruct)
		val INode node = NodeModelUtils.getNode(alt)
		if (depth > activeProfile.maximumAllowedNestingDepth) {
			TTCN3StatisticsProvider.getInstance.incrementCountStyle
			val message = "Alt statement nesting depth (" + depth + ") exceeds maximum allowed nesting depth (" +
				activeProfile.maximumAllowedNestingDepth + ")!"
			warning(
@@ -700,6 +711,8 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		if (!activeProfile.checkNoPermutationKeyword)
			return;
			
		TTCN3StatisticsProvider.getInstance.incrementCountStyle
		
		val INode node = NodeModelUtils.getNode(permutation)
		val message = "Keyword \"permutation\" is used!"
		warning(
@@ -718,6 +731,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
			return;

		if (type.pre != null && type.pre == 'anytype') {
			TTCN3StatisticsProvider.getInstance.incrementCountStyle
			val INode node = NodeModelUtils.getNode(type)
			val message = "Keyword \"anytype\" is used!"
			warning(
@@ -740,6 +754,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
			val baseTemplate = template.derived.template.findDesiredParent(TemplateDef)
			val INode node = NodeModelUtils.getNode(template)
			if (baseTemplate.derived != null) {
				TTCN3StatisticsProvider.getInstance.incrementCountStyle
				val message = "Template \"" + template.base.name + "\" modifies another modified template (\"" +
					baseTemplate.base.name + "\")!"
				warning(
@@ -838,6 +853,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		for (c : foundChilds) {
			val message = "Local definition is not at the beginning!"
			val INode node = NodeModelUtils.getNode(c)
			TTCN3StatisticsProvider.getInstance.incrementCountStyle
			warning(
				message,
				null, //TODO: struct feature
@@ -855,6 +871,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		val INode node = NodeModelUtils.getNode(o)
		if (configuredOrder.contains(o.eClass)) {
			if (params.hasOtherDefinitions) {
				TTCN3StatisticsProvider.getInstance.incrementCountStyle
				val message = "Local definition is not at the beginning!"
				warning(
					message,
@@ -866,6 +883,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
				);
			} else {
				if ((currentLocalDefinitionTypeOrderLevel < params.previousLocalDefinitionsOrderLevel)) {
					TTCN3StatisticsProvider.getInstance.incrementCountStyle
					val message = "Local definition order is not maintained as configured (" +
						configuredOrder.eClassesToString + ")!"
					warning(
@@ -924,6 +942,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		for (d : module.defs.definitions) {
			if (d.def instanceof ImportDef) {
				if (hasOtherDefs) {
					TTCN3StatisticsProvider.getInstance.incrementCountStyle
					val message = "Import statement is not at the beginning!"
					val INode node = NodeModelUtils.getNode(d)
					warning(
@@ -998,6 +1017,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		}

		if (idExists) {
			TTCN3StatisticsProvider.getInstance.incrementCountStyle
			val message = "Identifier \"" + detailDef.name + "\" on the module level has already been used in " +
				parentModule.name + "!"
			val INode node = NodeModelUtils.getNode(detailDef)
@@ -1122,6 +1142,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		}

		if (notReferenced) {
			TTCN3StatisticsProvider.getInstance.incrementCountStyle
			val message = "Definition for \"" + detailDef.name + "\" is never referenced!"
			val INode node = NodeModelUtils.getNode(detailDef)
			warning(
@@ -1145,6 +1166,8 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		if (!activeProfile.checkNoInlineTemplates)
			return;
		
		TTCN3StatisticsProvider.getInstance.incrementCountStyle
		
		val message = "Inline Template is used!"
		val INode node = NodeModelUtils.getNode(template)
		warning(
@@ -1193,6 +1216,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
			}

			if (overSpecified) {
				TTCN3StatisticsProvider.getInstance.incrementCountStyle
				warning(
					message,
					null, //TODO: EStructuralFeature
@@ -1208,6 +1232,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {

	private def boolean specifiedComponentResolved(TTCN3Reference parent, ComponentDef component) {
		if (Strings.isNullOrEmpty(component.name)) {
			TTCN3StatisticsProvider.getInstance.incrementCountStyle
			val message = "" + "Runs on component reference of \"" + parent.name +
				"\" cannot be resolved. It may not be possible to determine whether construct has an over-specific runs on clause!"
			val INode node = NodeModelUtils.getNode(parent)
@@ -1231,6 +1256,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {

		for (f : parent.getAllContentsOfType(FunctionInstance).map[it.ref]) {
			if (consideredAltOrFunc.contains(f)) {
				TTCN3StatisticsProvider.getInstance.incrementCountStyle
				val message = "" + "Possible cyclic call sequence: \"" + f.name + "\". Skipping..."
				val INode node = NodeModelUtils.getNode(f)
				info(
@@ -1249,6 +1275,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {

		for (a : parent.getAllContentsOfType(AltstepInstance).map[it.ref]) {
			if (consideredAltOrFunc.contains(a)) {
				TTCN3StatisticsProvider.getInstance.incrementCountStyle
				val message = "" + "Possible cyclic call sequence: \"" + a.name + "\". Skipping..."
				val INode node = NodeModelUtils.getNode(a)
				info(
@@ -1393,6 +1420,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
			}
			if ((current.eContainer as TemplateDef).derived != null) {
				if (consideredTemplates.contains((current.eContainer as TemplateDef).derived.template)) {
					TTCN3StatisticsProvider.getInstance.incrementCountStyle
					val message = "" + "Possible cyclic modifies sequence: \"" + template.name + "\". Skipping..."
					val INode node = NodeModelUtils.getNode(template)
					info(
@@ -1421,6 +1449,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		val module = parent.findDesiredParent(TTCN3Module)
		for (p : params) {
			if (p.isUnreferenced(module)) { // TODO: test this call and consider alternatives
				TTCN3StatisticsProvider.getInstance.incrementCountStyle
				val message = "Formal parameter \"" + (p as TTCN3Reference).name + "\" in definition for \"" +
					(parent as TTCN3Reference).name + "\" is never used!"
				val INode node = NodeModelUtils.getNode(p)
@@ -1472,6 +1501,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		if (variable.variableLocal) {
			val module = variable.findDesiredParent(TTCN3Module)
			if (variable.isUnreferenced(module)) {
				TTCN3StatisticsProvider.getInstance.incrementCountStyle
				val message = "Local definition for \"" + variable.name + "\" in definition of \"" + module.name +
					"\" is never used!"
				val INode node = NodeModelUtils.getNode(variable)
@@ -1511,6 +1541,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		if (parentModulePar == null && parentConstDef == null && parentTemplate == null) {
			if (value.bstring != null || value.integer != null || value.float != null || value.hstring != null ||
				value.ostring != null || value.charString != null) {
				TTCN3StatisticsProvider.getInstance.incrementCountStyle
				val message = "Literal value is used!"
				val INode node = NodeModelUtils.getNode(value)
				warning(
@@ -1574,6 +1605,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
				definition = d.def
			}
			if (!moduleHelper.typePermittedInRestrictedModule(moduleRestriction, definition.eClass)) {
				TTCN3StatisticsProvider.getInstance.incrementCountModularization
				val message = "Definition in " + moduleRestriction +
					" module is not of the permissible definition type(s)!"
				val INode node = NodeModelUtils.getNode(definition)
@@ -1589,6 +1621,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
				if (moduleRestriction == ModuleContentHelper.TestcasesModuleIDSubstring &&
					definition instanceof FunctionDef) {
					if (!(definition as FunctionDef).functionStartBehavior(module)) {
						TTCN3StatisticsProvider.getInstance.incrementCountModularization
						val message = "Definition in " + moduleRestriction +
							" module is not of the permissible definition type(s)! Function " +
							(definition as FunctionDef).name + " is never referenced in a start statement!"
@@ -1631,6 +1664,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		val moduleSize = node.getEndOffset() - node.getOffset();
		val referenceSize = activeProfile.getMaximumAllowedModuleSizeInBytes();
		if (moduleSize > referenceSize) {
			TTCN3StatisticsProvider.getInstance.incrementCountModularization
			val message = "Module \"" + module.name + "\" is greater (" + moduleSize +
				" bytes) than the maximum allowed module size (" + referenceSize + " bytes)!"
			warning(
@@ -1671,6 +1705,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		}

		if (!libCommonReferenceFound) {
			TTCN3StatisticsProvider.getInstance.incrementCountModularization
			val message = "Required import from \"" + activeProfile.getTypesAndValuesImportsLibNamesRegExp() +
				"\" not found!!"
			val INode node = NodeModelUtils.getNode(module)
@@ -1703,6 +1738,7 @@ class TTCN3Validator extends AbstractTTCN3Validator {
		}

		if (!libCommonReferenceFound) {
			TTCN3StatisticsProvider.getInstance.incrementCountModularization
			val message = "Required import from \"LibCommon_Sync\" not found!"
			val INode node = NodeModelUtils.getNode(module)
			warning(
@@ -1719,6 +1755,34 @@ class TTCN3Validator extends AbstractTTCN3Validator {
/**
* END: Test Suite Modularization ------------------------------------------------------------------------------
*/


/**
* BEGIN: Misc Features ------------------------------------------------------------------------------
*/
	@Check
	def addModuleToStatisticProvider(TTCN3Module module) {
		//TODO: do this only in standalone app?
		TTCN3StatisticsProvider.getInstance().addModule(module);
	}
	
	@Check
	def listImports(TTCN3Module module) {
		if (activeProfile.featureListImportedModuleNames || activeProfile.featureListImportedModuleFileNames
			|| activeProfile.featureListImportingModuleNames || activeProfile.featureListImportingModuleFileNames) {
			
			for (i : module.getAllContentsOfType(ImportDef)) {
				TTCN3StatisticsProvider.getInstance().addImport(module.name, i.moduleNamespace)
			}	
		}
	}


/**
* END: Misc Features ------------------------------------------------------------------------------
*/


//TODO: update error parameters
/*