[modelica] Initial implementation of Modelica support for PMD

This commit is contained in:
Anatoly Trosinenko 2019-09-28 16:21:58 +03:00
parent 78c8ea2749
commit 20bf4ad759
83 changed files with 6379 additions and 7 deletions

View File

@ -9,10 +9,10 @@
**PMD** is a source code analyzer. It finds common programming flaws like unused variables, empty catch blocks,
unnecessary object creation, and so forth. It supports Java, JavaScript, Salesforce.com Apex and Visualforce,
PLSQL, Apache Velocity, XML, XSL, Scala.
Modelica, PLSQL, Apache Velocity, XML, XSL, Scala.
Additionally it includes **CPD**, the copy-paste-detector. CPD finds duplicated code in
C/C++, C#, Dart, Fortran, Go, Groovy, Java, JavaScript, JSP, Kotlin, Lua, Matlab,
C/C++, C#, Dart, Fortran, Go, Groovy, Java, JavaScript, JSP, Kotlin, Lua, Matlab, Modelica,
Objective-C, Perl, PHP, PLSQL, Python, Ruby, Salesforce.com Apex, Scala, Swift and Visualforce.
## Source and Documentation

View File

@ -162,6 +162,11 @@
<artifactId>pmd-matlab</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-modelica</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-perl</artifactId>

View File

@ -66,7 +66,7 @@ public class BinaryDistributionIT extends AbstractBinaryDistributionTest {
result = PMDExecutor.runPMD(tempDir, "-h");
// note: the language "text" is provided by pmd-designer
result.assertExecutionResult(0, "apex, ecmascript, java, jsp, plsql, pom, scala, text, vf, vm, wsdl, xml, xsl");
result.assertExecutionResult(0, "apex, ecmascript, java, jsp, modelica, plsql, pom, scala, text, vf, vm, wsdl, xml, xsl");
result = PMDExecutor.runPMDRules(tempDir, srcDir, "src/test/resources/rulesets/sample-ruleset.xml");
result.assertExecutionResult(4, "", "JumbledIncrementer.java:8:");
@ -82,7 +82,7 @@ public class BinaryDistributionIT extends AbstractBinaryDistributionTest {
ExecutionResult result;
result = CpdExecutor.runCpd(tempDir, "-h");
result.assertExecutionResult(0, "Supported languages: [apex, cpp, cs, dart, ecmascript, fortran, go, groovy, java, jsp, kotlin, lua, matlab, objectivec, perl, php, plsql, python, ruby, scala, swift, vf]");
result.assertExecutionResult(0, "Supported languages: [apex, cpp, cs, dart, ecmascript, fortran, go, groovy, java, jsp, kotlin, lua, matlab, modelica, objectivec, perl, php, plsql, python, ruby, scala, swift, vf]");
result = CpdExecutor.runCpd(tempDir, "--minimum-tokens", "10", "--format", "text", "--files", srcDir);
result.assertExecutionResult(4, "Found a 10 line (55 tokens) duplication in the following files:");

File diff suppressed because it is too large Load Diff

83
pmd-modelica/pom.xml Normal file
View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>pmd-modelica</artifactId>
<name>PMD Modelica</name>
<parent>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd</artifactId>
<version>6.21.0-SNAPSHOT</version>
</parent>
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<useDefaultDelimiters>false</useDefaultDelimiters>
<delimiters>
<delimiter>${*}</delimiter>
</delimiters>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<inherited>true</inherited>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<target>
<ant antfile="src/main/ant/alljavacc.xml">
<property name="target" value="${project.build.directory}/generated-sources/javacc" />
<property name="javacc.jar" value="${settings.localRepository}/net/java/dev/javacc/javacc/${javacc.version}/javacc-${javacc.version}.jar" />
</ant>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-javacc-generated-sources</id>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/javacc</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-core</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,157 @@
<project name="pmd" default="alljavacc" basedir="../../">
<property name="javacc-home.path" value="target/lib" />
<target name="alljavacc"
description="Generates all JavaCC aspects within PMD Modelica"
depends="checkUpToDate,init,modelicajjtree,cleanup" />
<target name="checkUpToDate">
<uptodate property="javaccBuildNotRequired" targetfile="${target}/last-generated-timestamp">
<srcfiles dir="etc/grammar" includes="*.jj*"/>
</uptodate>
<echo message="up to date check: javaccBuildNotRequired=${javaccBuildNotRequired}"/>
</target>
<target name="init" unless="javaccBuildNotRequired">
<mkdir dir="${javacc-home.path}" />
<copy file="${javacc.jar}" tofile="${javacc-home.path}/javacc.jar" />
<mkdir dir="${target}"/>
<touch file="${target}/last-generated-timestamp"/>
</target>
<target name="cleanup">
<delete dir="${javacc-home.path}" />
</target>
<target name="modelicajjtree" description="Generates the Modelica parser and AST source files" unless="javaccBuildNotRequired">
<delete dir="${target}/net/sourceforge/pmd/lang/modelica/ast" />
<mkdir dir="${target}/net/sourceforge/pmd/lang/modelica/ast" />
<jjtree target="etc/grammar/Modelica.jjt"
outputdirectory="${target}/net/sourceforge/pmd/lang/modelica/ast"
javacchome="${javacc-home.path}" />
<!-- Ensure generated using CharStream interface -->
<javacc static="false"
usercharstream="true"
target="${target}/net/sourceforge/pmd/lang/modelica/ast/Modelica.jj"
outputdirectory="${target}/net/sourceforge/pmd/lang/modelica/ast"
javacchome="${javacc-home.path}" />
<delete file="${target}/net/sourceforge/pmd/lang/modelica/ast/Node.java" />
<delete file="${target}/net/sourceforge/pmd/lang/modelica/ast/SimpleNode.java" />
<delete file="${target}/net/sourceforge/pmd/lang/modelica/ast/CharStream.java" />
<delete file="${target}/net/sourceforge/pmd/lang/modelica/ast/TokenMgrError.java" />
<replace file="${target}/net/sourceforge/pmd/lang/modelica/ast/ModelicaParserTokenManager.java"
token="class ModelicaParserTokenManager"
value="class ModelicaParserTokenManager extends net.sourceforge.pmd.lang.ast.AbstractTokenManager" />
<replace file="${target}/net/sourceforge/pmd/lang/modelica/ast/ModelicaParser.java"
token="throw new Error"
value="throw new RuntimeException" />
<replace file="${target}/net/sourceforge/pmd/lang/modelica/ast/ParseException.java"
token="extends Exception"
value="extends net.sourceforge.pmd.lang.ast.ParseException" />
<replace file="${target}/net/sourceforge/pmd/lang/modelica/ast/ModelicaParserVisitor.java"
token="SimpleNode"
value="AbstractModelicaNode" />
<replace file="${target}/net/sourceforge/pmd/lang/modelica/ast/JJTModelicaParserState.java">
<replacetoken>public class</replacetoken>
<replacevalue><![CDATA[import net.sourceforge.pmd.lang.ast.Node;
public class]]></replacevalue>
</replace>
<replace file="${target}/net/sourceforge/pmd/lang/modelica/ast/Token.java">
<replacetoken><![CDATA[ default : return new Token(ofKind, image);
}
}
]]></replacetoken>
<replacevalue><![CDATA[
default : return new Token(ofKind, image);
}
}
]]></replacevalue>
</replace>
<replace file="${target}/net/sourceforge/pmd/lang/modelica/ast/Token.java">
<replacetoken>public class Token implements java.io.Serializable</replacetoken>
<replacevalue><![CDATA[import net.sourceforge.pmd.lang.ast.GenericToken;
public class Token implements GenericToken, java.io.Serializable]]></replacevalue>
</replace>
<!--Add implementation methods of GenericToken-->
<replace file="${target}/net/sourceforge/pmd/lang/modelica/ast/Token.java">
<replacetoken>public Token specialToken;</replacetoken>
<replacevalue><![CDATA[public Token specialToken;
@Override
public GenericToken getNext() {
return next;
}
@Override
public GenericToken getPreviousComment() {
return specialToken;
}
@Override
public String getImage() {
return image;
}
@Override
public int getBeginLine() {
return beginLine;
}
@Override
public int getEndLine() {
return endLine;
}
@Override
public int getBeginColumn() {
return beginColumn;
}
@Override
public int getEndColumn() {
return endColumn;
}
]]></replacevalue>
</replace>
<replace>
<fileset dir="${target}/net/sourceforge/pmd/lang/modelica/ast">
<include name="AST*.java" />
</fileset>
<replacetoken>SimpleNode</replacetoken>
<replacevalue>AbstractModelicaNode</replacevalue>
</replace>
<delete>
<fileset dir="${target}/net/sourceforge/pmd/lang/modelica/ast">
<include name="ASTStoredDefinition.java" />
<include name="ASTWithinClause.java" />
<include name="ASTElementList.java" />
<include name="ASTClassDefinition.java" />
<include name="ASTDerClassSpecifier.java" />
<include name="ASTEnumerationShortClassSpecifier.java" />
<include name="ASTExtendingLongClassSpecifier.java" />
<include name="ASTSimpleLongClassSpecifier.java" />
<include name="ASTSimpleShortClassSpecifier.java" />
<include name="ASTName.java" />
<include name="ASTComponentReference.java" />
<include name="ASTRenamingImportClause.java" />
<include name="ASTSingleDefinitionImportClause.java" />
<include name="ASTMultipleDefinitionImportClause.java" />
<include name="ASTUnqualifiedImportClause.java" />
</fileset>
</delete>
</target>
</project>

View File

@ -0,0 +1,13 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cpd;
import net.sourceforge.pmd.lang.modelica.ModelicaLanguageModule;
public class ModelicaLanguage extends AbstractLanguage {
public ModelicaLanguage() {
super(ModelicaLanguageModule.NAME, ModelicaLanguageModule.TERSE_NAME, new ModelicaTokenizer(), ".mo");
}
}

View File

@ -0,0 +1,67 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cpd;
import java.io.StringReader;
import net.sourceforge.pmd.cpd.internal.JavaCCTokenizer;
import net.sourceforge.pmd.cpd.token.JavaCCTokenFilter;
import net.sourceforge.pmd.lang.TokenManager;
import net.sourceforge.pmd.lang.ast.GenericToken;
import net.sourceforge.pmd.lang.modelica.ModelicaTokenManager;
import net.sourceforge.pmd.lang.modelica.ast.ModelicaParser;
import net.sourceforge.pmd.lang.modelica.ast.Token;
public class ModelicaTokenizer extends JavaCCTokenizer {
@Override
protected TokenManager getLexerForSource(SourceCode sourceCode) {
final StringBuilder stringBuilder = sourceCode.getCodeBuffer();
return new ModelicaTokenManager(new StringReader(stringBuilder.toString()));
}
@Override
protected JavaCCTokenFilter getTokenFilter(TokenManager tokenManager) {
return new ModelicaTokenFilter(tokenManager);
}
public static class ModelicaTokenFilter extends JavaCCTokenFilter {
private boolean discardingWithinAndImport = false;
private boolean discardingAnnotation = false;
ModelicaTokenFilter(TokenManager tokenManager) {
super(tokenManager);
}
private void skipWithinAndImport(Token currentToken) {
final int type = currentToken.kind;
if (type == ModelicaParser.IMPORT || type == ModelicaParser.WITHIN) {
discardingWithinAndImport = true;
} else if (discardingWithinAndImport && type == ModelicaParser.SC) {
discardingWithinAndImport = false;
}
}
private void skipAnnotation(Token currentToken) {
final int type = currentToken.kind;
if (type == ModelicaParser.ANNOTATION) {
discardingAnnotation = true;
} else if (discardingAnnotation && type == ModelicaParser.SC) {
discardingAnnotation = false;
}
}
@Override
protected void analyzeToken(GenericToken currentToken) {
skipWithinAndImport((Token) currentToken);
skipAnnotation((Token) currentToken);
}
@Override
protected boolean isLanguageSpecificDiscarding() {
return discardingWithinAndImport || discardingAnnotation;
}
}
}

View File

@ -0,0 +1,49 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica;
import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler;
import net.sourceforge.pmd.lang.Parser;
import net.sourceforge.pmd.lang.ParserOptions;
import net.sourceforge.pmd.lang.VisitorStarter;
import net.sourceforge.pmd.lang.XPathHandler;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.xpath.DefaultASTXPathHandler;
import net.sourceforge.pmd.lang.modelica.ast.ASTStoredDefinition;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaSymbolFacade;
import net.sourceforge.pmd.lang.modelica.rule.ModelicaRuleViolationFactory;
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
public class ModelicaHandler extends AbstractLanguageVersionHandler {
@Override
public XPathHandler getXPathHandler() {
return new DefaultASTXPathHandler();
}
@Override
public RuleViolationFactory getRuleViolationFactory() {
return ModelicaRuleViolationFactory.INSTANCE;
}
@Override
public Parser getParser(ParserOptions parserOptions) {
return new ModelicaParser(parserOptions);
}
@Override
public VisitorStarter getSymbolFacade() {
return new VisitorStarter() {
@Override
public void start(Node rootNode) {
new ModelicaSymbolFacade().initializeWith((ASTStoredDefinition) rootNode);
}
};
}
@Override
public VisitorStarter getSymbolFacade(ClassLoader classLoader) {
return getSymbolFacade();
}
}

View File

@ -0,0 +1,18 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica;
import net.sourceforge.pmd.lang.BaseLanguageModule;
import net.sourceforge.pmd.lang.modelica.rule.ModelicaRuleChainVisitor;
public class ModelicaLanguageModule extends BaseLanguageModule {
public static final String NAME = "Modelica";
public static final String TERSE_NAME = "modelica";
public ModelicaLanguageModule() {
super(NAME, null, TERSE_NAME, ModelicaRuleChainVisitor.class, "mo");
addVersion("", new ModelicaHandler(), true);
}
}

View File

@ -0,0 +1,45 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica;
import java.io.Reader;
import java.util.HashMap;
import java.util.Map;
import net.sourceforge.pmd.lang.AbstractParser;
import net.sourceforge.pmd.lang.ParserOptions;
import net.sourceforge.pmd.lang.TokenManager;
import net.sourceforge.pmd.lang.ast.AbstractTokenManager;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.ParseException;
import net.sourceforge.pmd.lang.ast.SimpleCharStream;
public class ModelicaParser extends AbstractParser {
public ModelicaParser(final ParserOptions parserOptions) {
super(parserOptions);
}
@Override
protected TokenManager createTokenManager(Reader source) {
return new ModelicaTokenManager(source);
}
@Override
public boolean canParse() {
return true;
}
@Override
public Node parse(String fileName, Reader source) throws ParseException {
AbstractTokenManager.setFileName(fileName);
return new net.sourceforge.pmd.lang.modelica.ast.ModelicaParser(new SimpleCharStream(source)).StoredDefinition();
}
@Override
public Map<Integer, String> getSuppressMap() {
return new HashMap<Integer, String>(); // TODO
}
}

View File

@ -0,0 +1,31 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica;
import java.io.Reader;
import net.sourceforge.pmd.lang.TokenManager;
import net.sourceforge.pmd.lang.ast.AbstractTokenManager;
import net.sourceforge.pmd.lang.ast.SimpleCharStream;
import net.sourceforge.pmd.lang.modelica.ast.ModelicaParserTokenManager;
public class ModelicaTokenManager implements TokenManager {
private final ModelicaParserTokenManager modelicaParserTokenManager;
public ModelicaTokenManager(final Reader source) {
modelicaParserTokenManager = new ModelicaParserTokenManager(new SimpleCharStream(source));
}
@Override
public Object getNextToken() {
return modelicaParserTokenManager.getNextToken();
}
@Override
public void setFileName(String fileName) {
AbstractTokenManager.setFileName(fileName);
}
}

View File

@ -0,0 +1,78 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaClassSpecialization;
public class ASTClassDefinition extends AbstractModelicaNode {
private ASTClassPrefixes prefixes;
private ModelicaClassSpecialization specialization;
private ModelicaClassSpecifierNode specifier;
public ASTClassDefinition(int id) {
super(id);
}
public ASTClassDefinition(ModelicaParser p, int id) {
super(p, id);
}
public boolean isPartial() {
return prefixes.getFirstChildOfType(ASTPartialClause.class) != null;
}
public boolean isEncapsulated() {
return getFirstChildOfType(ASTEncapsulatedClause.class) != null;
}
public ModelicaClassSpecialization getSpecialization() {
return specialization;
}
public ModelicaClassSpecifierNode getClassSpecifier() {
return specifier;
}
private void checkSpecialization(Class<?> clauseClass, ModelicaClassSpecialization restriction) {
if (prefixes.getFirstChildOfType(clauseClass) != null) {
assert specialization == null;
specialization = restriction;
}
}
private void detectSpecialization() {
checkSpecialization(ASTClassClause.class, ModelicaClassSpecialization.CLASS);
checkSpecialization(ASTModelClause.class, ModelicaClassSpecialization.MODEL);
checkSpecialization(ASTRecordClause.class, ModelicaClassSpecialization.RECORD);
checkSpecialization(ASTOperatorRecordClause.class, ModelicaClassSpecialization.OPERATOR_RECORD);
checkSpecialization(ASTBlockClause.class, ModelicaClassSpecialization.BLOCK);
checkSpecialization(ASTConnectorClause.class, ModelicaClassSpecialization.CONNECTOR);
checkSpecialization(ASTExpandableConnectorClause.class, ModelicaClassSpecialization.EXPANDABLE_CONNECTOR);
checkSpecialization(ASTTypeClause.class, ModelicaClassSpecialization.TYPE);
checkSpecialization(ASTPackageClause.class, ModelicaClassSpecialization.PACKAGE);
checkSpecialization(ASTOperatorClause.class, ModelicaClassSpecialization.OPERATOR);
ASTFunctionClause functionOrNull = prefixes.getFirstChildOfType(ASTFunctionClause.class);
if (functionOrNull != null) {
boolean isPure = functionOrNull.getFirstChildOfType(ASTPureClause.class) != null;
boolean isOperator = functionOrNull.getFirstChildOfType(ASTOperatorClause.class) != null;
assert specialization == null;
specialization = ModelicaClassSpecialization.getFunctionSpecialization(isPure, isOperator);
}
assert specialization != null;
}
@Override
public void jjtClose() {
super.jjtClose();
prefixes = getFirstChildOfType(ASTClassPrefixes.class);
specifier = getFirstChildOfType(ASTClassSpecifier.class).getFirstChildOfType(ModelicaClassSpecifierNode.class);
detectSpecialization();
}
@Override
public Object jjtAccept(ModelicaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
}

View File

@ -0,0 +1,77 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
import net.sourceforge.pmd.lang.modelica.resolver.CompositeName;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionResult;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionState;
import net.sourceforge.pmd.lang.modelica.resolver.ResolvableEntity;
public final class ASTComponentReference extends AbstractModelicaNode implements ResolvableModelicaNode {
private String[] nameComponentsWithoutSubscripts;
private boolean absolute;
private ResolutionResult<ResolvableEntity> resolutionCandidates;
ASTComponentReference(int id) {
super(id);
}
ASTComponentReference(ModelicaParser p, int id) {
super(p, id);
}
void markAbsolute() {
absolute = true;
}
/**
* Returns whether this reference is absolute (starts with a dot), such as
* <code>y = .Modelica.Math.cos(x)</code>.
*/
boolean isAbsolute() {
return absolute;
}
/**
* Returns a {@link CompositeName} object representing the lexical reference with subscripts being ignored, if any.
*/
public CompositeName getCompositeNameWithoutSubscripts() {
return CompositeName.create(absolute, nameComponentsWithoutSubscripts);
}
/**
* Returns resolution candidates for the referred component (and <b>not</b> dereferencing its type, etc.).
*
* We do not decide on entity type on behalf of the rule code, since this may introduce false negatives.
*/
@Override
public ResolutionResult<ResolvableEntity> getResolutionCandidates() {
if (resolutionCandidates == null) {
resolutionCandidates = getMostSpecificScope().safeResolveLexically(ResolvableEntity.class, ResolutionState.forComponentReference(), getCompositeNameWithoutSubscripts());
}
return resolutionCandidates;
}
// For Rule Designer
public String getResolvedTo() {
return Helper.getResolvedTo(getResolutionCandidates());
}
@Override
public Object jjtAccept(ModelicaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
@Override
public void jjtClose() {
super.jjtClose();
nameComponentsWithoutSubscripts = new String[jjtGetNumChildren()];
for (int i = 0; i < nameComponentsWithoutSubscripts.length; ++i) {
String name = jjtGetChild(i).getFirstChildOfType(ASTSimpleName.class).getImage();
nameComponentsWithoutSubscripts[i] = name;
}
}
}

View File

@ -0,0 +1,20 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
public final class ASTDerClassSpecifier extends AbstractModelicaClassSpecifierNode {
ASTDerClassSpecifier(int id) {
super(id);
}
ASTDerClassSpecifier(ModelicaParser p, int id) {
super(p, id);
}
@Override
public Object jjtAccept(ModelicaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
}

View File

@ -0,0 +1,30 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
public class ASTElementList extends AbstractModelicaNode {
private Visibility visibility;
public ASTElementList(int id) {
super(id);
}
public ASTElementList(ModelicaParser p, int id) {
super(p, id);
}
void setVisibility(Visibility visibility) {
this.visibility = visibility;
}
public Visibility getVisibility() {
return visibility;
}
@Override
public Object jjtAccept(ModelicaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
}

View File

@ -0,0 +1,20 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
public final class ASTEnumerationShortClassSpecifier extends AbstractModelicaClassSpecifierNode {
ASTEnumerationShortClassSpecifier(int id) {
super(id);
}
ASTEnumerationShortClassSpecifier(ModelicaParser p, int id) {
super(p, id);
}
@Override
public Object jjtAccept(ModelicaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
}

View File

@ -0,0 +1,29 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaClassType;
public final class ASTExtendingLongClassSpecifier extends AbstractModelicaClassSpecifierNode {
ASTExtendingLongClassSpecifier(int id) {
super(id);
}
ASTExtendingLongClassSpecifier(ModelicaParser p, int id) {
super(p, id);
}
@Override
public Object jjtAccept(ModelicaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
@Override
public void populateExtendsAndImports(ModelicaClassType classTypeDeclaration) {
super.populateExtendsAndImports(classTypeDeclaration);
pushExtendsAndImports(classTypeDeclaration, getFirstChildOfType(ASTComposition.class));
// TODO
}
}

View File

@ -0,0 +1,63 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
import java.util.HashSet;
import java.util.Set;
import net.sourceforge.pmd.lang.modelica.resolver.CompositeName;
import net.sourceforge.pmd.lang.modelica.resolver.InternalModelicaResolverApi;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaDeclaration;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaScope;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionContext;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionResult;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionState;
import net.sourceforge.pmd.lang.modelica.resolver.Watchdog;
public final class ASTMultipleDefinitionImportClause extends AbstractModelicaImportClause {
private ASTName importFrom;
private Set<String> importedNames = new HashSet<>();
ASTMultipleDefinitionImportClause(int id) {
super(id);
}
ASTMultipleDefinitionImportClause(ModelicaParser p, int id) {
super(p, id);
}
@Override
public Object jjtAccept(ModelicaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
@Override
public void jjtClose() {
super.jjtClose();
importFrom = getFirstChildOfType(ASTName.class);
ASTImportList importList = getFirstChildOfType(ASTImportList.class);
for (int i = 0; i < importList.jjtGetNumChildren(); ++i) {
ASTSimpleName namePart = (ASTSimpleName) importList.jjtGetChild(i);
importedNames.add(namePart.getImage());
}
}
@Override
protected ResolutionResult<ModelicaDeclaration> getCacheableImportSources(ResolutionState state, ModelicaScope scope) {
return scope.safeResolveLexically(ModelicaDeclaration.class, state, importFrom.getCompositeName());
}
@Override
protected void fetchImportedClassesFromSource(ResolutionContext result, ModelicaDeclaration source, String simpleName) throws Watchdog.CountdownException {
if (importedNames.contains(simpleName)) {
InternalModelicaResolverApi.resolveFurtherNameComponents(source, result, CompositeName.create(simpleName));
}
}
@Override
public boolean isQualified() {
return true;
}
}

View File

@ -0,0 +1,85 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
import net.sourceforge.pmd.lang.modelica.resolver.CompositeName;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionResult;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionState;
import net.sourceforge.pmd.lang.modelica.resolver.ResolvableEntity;
public final class ASTName extends AbstractModelicaNode implements ResolvableModelicaNode {
private String[] nameComponents;
private ResolutionResult<ResolvableEntity> resolutionCandidates;
private boolean absolute = false;
ASTName(int id) {
super(id);
}
ASTName(ModelicaParser p, int id) {
super(p, id);
}
@Override
public Object jjtAccept(ModelicaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
@Override
public void jjtClose() {
super.jjtClose();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < jjtGetNumChildren(); ++i) {
if (i != 0 || absolute) {
sb.append('.');
}
sb.append(((ASTSimpleName) jjtGetChild(i)).getImage());
}
setImage(sb.toString());
nameComponents = new String[jjtGetNumChildren()];
for (int i = 0; i < jjtGetNumChildren(); ++i) {
nameComponents[i] = jjtGetChild(i).getImage();
}
}
void markAbsolute() {
absolute = true;
}
/**
* Returns whether this reference is absolute (starts with a dot), such as
* <code>.Modelica.Blocks.Continuous.Filter</code>.
*/
public boolean isAbsolute() {
return absolute;
}
/**
* Returns a {@link CompositeName} object representing a lexical reference contained in this node.
*/
public CompositeName getCompositeName() {
return CompositeName.create(absolute, nameComponents);
}
/**
* Returns resolution candidates for the referred entity.
*
* We do not decide on entity type on behalf of the rule code, since this may introduce false negatives.
*/
@Override
public ResolutionResult<ResolvableEntity> getResolutionCandidates() {
if (resolutionCandidates == null) {
resolutionCandidates = getMostSpecificScope().safeResolveLexically(ResolvableEntity.class, ResolutionState.forType(), getCompositeName());
}
return resolutionCandidates;
}
// For Rule Designer
public String getResolvedTo() {
return Helper.getResolvedTo(getResolutionCandidates());
}
}

View File

@ -0,0 +1,54 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaDeclaration;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaScope;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionContext;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionResult;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionState;
public final class ASTRenamingImportClause extends AbstractModelicaImportClause {
private ASTName importWhat;
private String renamedTo;
ASTRenamingImportClause(int id) {
super(id);
}
ASTRenamingImportClause(ModelicaParser p, int id) {
super(p, id);
}
@Override
public Object jjtAccept(ModelicaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
@Override
public void jjtClose() {
super.jjtClose();
importWhat = getFirstChildOfType(ASTName.class);
renamedTo = getFirstChildOfType(ASTSimpleName.class).getImage();
}
@Override
protected ResolutionResult<ModelicaDeclaration> getCacheableImportSources(ResolutionState state, ModelicaScope scope) {
return scope.safeResolveLexically(ModelicaDeclaration.class, state, importWhat.getCompositeName());
}
@Override
protected void fetchImportedClassesFromSource(ResolutionContext result, ModelicaDeclaration source, String simpleName) {
if (renamedTo.equals(simpleName)) {
result.addCandidate(source);
}
}
@Override
public boolean isQualified() {
return true;
}
}

View File

@ -0,0 +1,28 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaClassType;
public final class ASTSimpleLongClassSpecifier extends AbstractModelicaClassSpecifierNode {
ASTSimpleLongClassSpecifier(int id) {
super(id);
}
ASTSimpleLongClassSpecifier(ModelicaParser p, int id) {
super(p, id);
}
@Override
public Object jjtAccept(ModelicaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
@Override
void populateExtendsAndImports(ModelicaClassType classTypeDeclaration) {
super.populateExtendsAndImports(classTypeDeclaration);
pushExtendsAndImports(classTypeDeclaration, getFirstChildOfType(ASTComposition.class));
}
}

View File

@ -0,0 +1,33 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
import net.sourceforge.pmd.lang.modelica.resolver.InternalModelicaResolverApi;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaClassType;
public final class ASTSimpleShortClassSpecifier extends AbstractModelicaClassSpecifierNode {
ASTSimpleShortClassSpecifier(int id) {
super(id);
}
ASTSimpleShortClassSpecifier(ModelicaParser p, int id) {
super(p, id);
}
@Override
public Object jjtAccept(ModelicaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
@Override
public void populateExtendsAndImports(ModelicaClassType classTypeDeclaration) {
super.populateExtendsAndImports(classTypeDeclaration);
InternalModelicaResolverApi.addExtendToClass(
classTypeDeclaration,
Visibility.UNSPEC,
getFirstChildOfType(ASTName.class).getCompositeName()
);
}
}

View File

@ -0,0 +1,54 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaDeclaration;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaScope;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionContext;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionResult;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionState;
public class ASTSingleDefinitionImportClause extends AbstractModelicaImportClause {
private ASTName importWhat;
private String importedName;
ASTSingleDefinitionImportClause(int id) {
super(id);
}
ASTSingleDefinitionImportClause(ModelicaParser p, int id) {
super(p, id);
}
@Override
public Object jjtAccept(ModelicaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
@Override
public void jjtClose() {
super.jjtClose();
importWhat = getFirstChildOfType(ASTName.class);
importedName = importWhat.jjtGetChild(importWhat.jjtGetNumChildren() - 1).getImage();
}
@Override
protected ResolutionResult<ModelicaDeclaration> getCacheableImportSources(ResolutionState state, ModelicaScope scope) {
return scope.safeResolveLexically(ModelicaDeclaration.class, state, importWhat.getCompositeName());
}
@Override
protected void fetchImportedClassesFromSource(ResolutionContext result, ModelicaDeclaration source, String simpleName) {
if (importedName.equals(simpleName)) {
result.addCandidate(source);
}
}
@Override
public boolean isQualified() {
return true;
}
}

View File

@ -0,0 +1,55 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
import net.sourceforge.pmd.lang.modelica.resolver.CompositeName;
/**
* A representation of a Modelica source code file.
*/
public class ASTStoredDefinition extends AbstractModelicaNode {
private boolean hasBOM = false;
ASTStoredDefinition(int id) {
super(id);
}
ASTStoredDefinition(ModelicaParser p, int id) {
super(p, id);
}
@Override
public Object jjtAccept(ModelicaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
void markHasBOM() {
hasBOM = true;
}
/**
* Returns whether this source file contains Byte Order Mark.
*/
public boolean getHasBOM() {
return hasBOM;
}
@Override
public void jjtClose() {
super.jjtClose();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < jjtGetNumChildren(); ++i) {
AbstractModelicaNode child = (AbstractModelicaNode) jjtGetChild(i);
if (child instanceof ASTWithinClause) {
if (sb.length() > 0) {
sb.append(CompositeName.NAME_COMPONENT_SEPARATOR);
}
sb.append(child.getImage());
}
}
setImage(sb.toString());
}
}

View File

@ -0,0 +1,54 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
import net.sourceforge.pmd.lang.modelica.resolver.CompositeName;
import net.sourceforge.pmd.lang.modelica.resolver.InternalModelicaResolverApi;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaDeclaration;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaScope;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionContext;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionResult;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionState;
import net.sourceforge.pmd.lang.modelica.resolver.Watchdog;
public final class ASTUnqualifiedImportClause extends AbstractModelicaImportClause {
private ASTName importFromWhere;
ASTUnqualifiedImportClause(int id) {
super(id);
}
ASTUnqualifiedImportClause(ModelicaParser p, int id) {
super(p, id);
}
@Override
public Object jjtAccept(ModelicaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
@Override
public void jjtClose() {
super.jjtClose();
importFromWhere = getFirstChildOfType(ASTName.class);
}
@Override
protected ResolutionResult<ModelicaDeclaration> getCacheableImportSources(ResolutionState state, ModelicaScope scope) {
return scope.safeResolveLexically(ModelicaDeclaration.class, state, importFromWhere.getCompositeName());
}
@Override
protected void fetchImportedClassesFromSource(ResolutionContext result, ModelicaDeclaration source, String simpleName) throws Watchdog.CountdownException {
result.watchdogTick();
InternalModelicaResolverApi.resolveFurtherNameComponents(source, result, CompositeName.create(simpleName));
}
@Override
public boolean isQualified() {
return false;
}
}

View File

@ -0,0 +1,32 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
public final class ASTWithinClause extends AbstractModelicaNode {
ASTWithinClause(int id) {
super(id);
}
ASTWithinClause(ModelicaParser p, int id) {
super(p, id);
}
@Override
public Object jjtAccept(ModelicaParserVisitor visitor, Object data) {
return visitor.visit(this, data);
}
@Override
public void jjtClose() {
super.jjtClose();
ASTName name = getFirstChildOfType(ASTName.class);
if (name != null) {
setImage(name.getImage());
} else {
setImage("");
}
}
}

View File

@ -0,0 +1,70 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
import net.sourceforge.pmd.lang.modelica.resolver.InternalModelicaResolverApi;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaClassType;
/**
* Common parent for class-specifier nodes, see {@link ModelicaClassSpecifierNode} for public API.
*/
abstract class AbstractModelicaClassSpecifierNode extends AbstractModelicaNode implements ModelicaClassSpecifierNode {
AbstractModelicaClassSpecifierNode(int id) {
super(id);
}
AbstractModelicaClassSpecifierNode(ModelicaParser parser, int id) {
super(parser, id);
}
@Override
public void jjtClose() {
super.jjtClose();
setImage(getFirstChildOfType(ASTSimpleName.class).getImage());
}
/**
* Fills in the class definition with <code>extends</code> and <code>import</code> clauses contained in this AST node.
*
* @param classTypeDeclaration a class declaration object corresponding to this AST node
*/
void populateExtendsAndImports(ModelicaClassType classTypeDeclaration) {
// by default, do nothing
}
private void pushExtendsAndImportsFromList(ModelicaClassType classTypeDeclaration, ASTElementList listNode) {
for (int i = 0; i < listNode.jjtGetNumChildren(); ++i) {
AbstractModelicaNode child = (AbstractModelicaNode) listNode.jjtGetChild(i);
if (child instanceof ASTExtendsClause) {
InternalModelicaResolverApi.addExtendToClass(
classTypeDeclaration,
listNode.getVisibility(),
child.getFirstChildOfType(ASTName.class).getCompositeName()
);
}
if (child instanceof ASTImportClause) {
InternalModelicaResolverApi.addImportToClass(
classTypeDeclaration,
listNode.getVisibility(),
child.getFirstChildOfType(ModelicaImportClause.class)
);
}
}
}
void pushExtendsAndImports(ModelicaClassType classTypeDeclaration, ASTComposition composition) {
for (int i = 0; i < composition.jjtGetNumChildren(); ++i) {
ModelicaNode maybeElementList = composition.jjtGetChild(i);
if (maybeElementList instanceof ASTElementList) {
pushExtendsAndImportsFromList(classTypeDeclaration, (ASTElementList) maybeElementList);
}
}
}
@Override
public String getSimpleClassName() {
return getImage();
}
}

View File

@ -0,0 +1,68 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaDeclaration;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaScope;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionContext;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionResult;
import net.sourceforge.pmd.lang.modelica.resolver.ResolutionState;
import net.sourceforge.pmd.lang.modelica.resolver.Watchdog;
/**
* Common internal machinery for various import clauses to describe themselves to resolver.
*/
abstract class AbstractModelicaImportClause extends AbstractModelicaNode implements ModelicaImportClause {
private ResolutionResult<ModelicaDeclaration> importSourcesCache;
AbstractModelicaImportClause(int id) {
super(id);
}
AbstractModelicaImportClause(ModelicaParser parser, int id) {
super(parser, id);
}
/**
* Some import clauses are considered "qualified", some "unqualified", the former being processed first
* while looking up some name. See "5.3.1 Simple Name Lookup" from MLS 3.4.
*
* @return Whether this kind of import is considered "qualified"
*/
abstract boolean isQualified();
/**
* A template method to be used by {@link resolveSimpleName}. Usually used to fetch the lexically referenced
* class in the corresponding import statement.
*/
protected abstract ResolutionResult<ModelicaDeclaration> getCacheableImportSources(ResolutionState state, ModelicaScope scope);
/**
* A template method to be used by {@link resolveSimpleName}. Usually used to try to fetch declarations for
* <code>simpleName</code> from particular <i>source</i> returned by {@link getCacheableImportSources}.
*/
protected abstract void fetchImportedClassesFromSource(ResolutionContext result, ModelicaDeclaration source, String simpleName) throws Watchdog.CountdownException;
/**
* Tries to resolve the specified name via this import clause.
*
* @param result Resolution context
* @param simpleName Name to resolve
* @throws Watchdog.CountdownException if too many resolution steps were performed
*/
final void resolveSimpleName(ResolutionContext result, String simpleName) throws Watchdog.CountdownException {
// No need to re-resolve if already resolved successfully
if (importSourcesCache == null || importSourcesCache.wasTimedOut()) {
importSourcesCache = getCacheableImportSources(result.getState(), getMostSpecificScope().getParent());
}
for (ModelicaDeclaration source : importSourcesCache.getBestCandidates()) {
fetchImportedClassesFromSource(result, source, simpleName);
}
result.markHidingPoint();
for (ModelicaDeclaration source : importSourcesCache.getHiddenCandidates()) {
fetchImportedClassesFromSource(result, source, simpleName);
}
}
}

View File

@ -0,0 +1,93 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.modelica.ast;
import net.sourceforge.pmd.lang.ast.AbstractNode;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.modelica.resolver.ModelicaScope;
/**
* Abstract base class for all nodes parsed by {@link ModelicaParser}.
*
* Please note that some of these nodes are autogenerated and placed to
* <code>pmd-modelica/target/generated-sources/javacc</code> by the build script. Those
* located here are deleted from autogenerated sources after build.
*
* @see ModelicaNode for public API.
*/
abstract class AbstractModelicaNode extends AbstractNode implements Node, ModelicaNode {
private ModelicaParser parser;
private ModelicaScope ownScope;
AbstractModelicaNode(int id) {
super(id);
}
AbstractModelicaNode(ModelicaParser parser, int id) {
super(id);
this.parser = parser;
}
@Override
public abstract Object jjtAccept(ModelicaParserVisitor visitor, Object data);
@Override
public String getXPathNodeName() {
return getClass().getSimpleName().substring(3);
}
@Override
public ModelicaNode jjtGetParent() {
return (ModelicaNode) super.jjtGetParent();
}
@Override
public ModelicaNode jjtGetChild(int index) {
return (ModelicaNode) super.jjtGetChild(index);
}
@Override
public void jjtOpen() {
if (beginLine == -1 && parser.token.next != null) {
beginLine = parser.token.next.beginLine;
beginColumn = parser.token.next.beginColumn;
}
}
@Override
public void jjtClose() {
if (beginLine == -1 && (children == null || children.length == 0)) {
beginColumn = parser.token.beginColumn;
}
if (beginLine == -1) {
beginLine = parser.token.beginLine;
}
endLine = parser.token.endLine;
endColumn = parser.token.endColumn;
}
@Override
public ModelicaScope getContainingScope() {
return ((AbstractModelicaNode) parent).getMostSpecificScope();
}
@Override
public ModelicaScope getMostSpecificScope() {
if (ownScope == null) {
return getContainingScope();
} else {
return ownScope;
}
}
/**
* For resolver, set the lexical scope defined by this node, if any.
*
* @param scope Scope defined by this specific node
*/
void setOwnScope(ModelicaScope scope) {
ownScope = scope;
}
}

Some files were not shown because too many files have changed in this diff Show More