Merge branch 'grammar-isolate-version-checks' into java-grammar

This commit is contained in:
Clément Fournier
2019-12-11 20:41:11 +01:00
15 changed files with 668 additions and 351 deletions

File diff suppressed because it is too large Load Diff

View File

@ -18,6 +18,11 @@ import net.sourceforge.pmd.lang.java.qname.JavaTypeQualifiedName;
*/
public interface ASTAnyTypeDeclaration extends TypeNode, JavaQualifiableNode, AccessNode, JavaNode {
default String getSimpleName() {
return getImage();
}
/**
* Finds the type kind of this declaration.
*

View File

@ -80,6 +80,12 @@ public final class ASTConstructorCall extends AbstractJavaExpr implements ASTPri
return (ASTArgumentList) jjtGetChild(idx);
}
/** Returns true if type arguments to the constructed instance's type are inferred. */
public boolean usesDiamondTypeArgs() {
ASTTypeArguments targs = getTypeNode().getTypeArguments();
return targs != null && targs.isDiamond();
}
/**
* Returns the type node.

View File

@ -130,7 +130,19 @@ public final class ASTNumericLiteral extends AbstractLiteral implements ASTLiter
return getImage().replaceAll("_++", "");
}
private int getIntBase() {
/**
* Returns true if this is an integral literal, ie either a long or
* an integer literal. Otherwise, this is a floating point literal.
*/
public boolean isIntegral() {
return isIntegral;
}
/**
* Returns the base of the literal, eg 8 for an octal literal,
* 10 for a decimal literal, etc.
*/
public int getBase() {
final String image = getImage().toLowerCase(Locale.ROOT);
if (image.startsWith("0x")) {
return 16;
@ -161,7 +173,7 @@ public final class ASTNumericLiteral extends AbstractLiteral implements ASTLiter
public long getValueAsLong() {
if (isIntegral) {
// Using BigInteger to allow parsing 0x8000000000000000+ numbers as negative instead of a NumberFormatException
BigInteger bigInt = new BigInteger(stripIntValue(), getIntBase());
BigInteger bigInt = new BigInteger(stripIntValue(), getBase());
return bigInt.longValue();
} else {
return (long) getValueAsDouble();

View File

@ -4,8 +4,13 @@
package net.sourceforge.pmd.lang.java.ast;
import java.util.Collections;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.internal.util.IteratorUtil;
/**
* Try statement node.
@ -51,6 +56,16 @@ public final class ASTTryStatement extends AbstractJavaNode {
return jjtGetChild(0) instanceof ASTResourceList;
}
@Nullable
public ASTResourceList getResourceList() {
return AstImplUtil.getChildAs(this, 0, ASTResourceList.class);
}
public List<ASTResource> getResources() {
ASTResourceList list = getResourceList();
return list == null ? Collections.emptyList() : IteratorUtil.toList(list.iterator());
}
/**
* Returns the catch statement nodes of this try statement.

View File

@ -10,6 +10,7 @@ import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.ParserOptions;
import net.sourceforge.pmd.lang.ast.AbstractTokenManager;
import net.sourceforge.pmd.lang.ast.JavaCharStream;
import net.sourceforge.pmd.lang.java.ast.internal.LanguageLevelChecker;
import net.sourceforge.pmd.lang.java.qname.JavaOperationQualifiedName;
import net.sourceforge.pmd.lang.java.qname.JavaTypeQualifiedName;
import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition;
@ -63,18 +64,19 @@ public final class InternalApiBridge {
}
}
public static ASTCompilationUnit parseInternal(String fileName, Reader source, int jdkVersion, boolean preview, ParserOptions options) {
public static ASTCompilationUnit parseInternal(String fileName, Reader source, LanguageLevelChecker<?> checker, ParserOptions options) {
JavaParser parser = new JavaParser(new JavaCharStream(source));
String suppressMarker = options.getSuppressMarker();
if (suppressMarker != null) {
parser.setSuppressMarker(suppressMarker);
}
parser.setJdkVersion(jdkVersion);
parser.setPreview(preview);
parser.setJdkVersion(checker.getJdkVersion());
parser.setPreview(checker.isPreviewEnabled());
AbstractTokenManager.setFileName(fileName);
ASTCompilationUnit acu = parser.CompilationUnit();
acu.setNoPmdComments(parser.getSuppressMap());
checker.check(acu);
return acu;
}

View File

@ -13,4 +13,35 @@ package net.sourceforge.pmd.lang.java.ast;
* @since 7.0.0
*/
public class SideEffectingVisitorAdapter<T> implements SideEffectingVisitor<T> {
public void visit(ASTAnnotation node, T data) {
visit((JavaNode) node, data);
}
@Override
public void visit(ASTSingleMemberAnnotation node, T data) {
visit((ASTAnnotation) node, data);
}
@Override
public void visit(ASTNormalAnnotation node, T data) {
visit((ASTAnnotation) node, data);
}
@Override
public void visit(ASTMarkerAnnotation node, T data) {
visit((ASTAnnotation) node, data);
}
// TODO delegation
public void visit(ASTSwitchLabeledRule node, T data) {
visit((JavaNode) node, data);
}
public void visit(ASTAnyTypeDeclaration node, T data) {
visit((JavaNode) node, data);
}
}

View File

@ -0,0 +1,61 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.ast.internal;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ParseException;
/**
* Strategy for reporting language-feature violations, for use by a
* {@link LanguageLevelChecker}. For example, {@link ReportingStrategy#reporterThatThrows()}
* produces a checker that throws a parse exception. It would be trivial
* to make eg a checker that eg collects all warnings instead of failing
* on the first one.
*
* @param <T> Type of object accumulating violations
*/
public interface ReportingStrategy<T> {
/** Create a blank accumulator before performing the check. */
T createAccumulator();
/** Consume the accumulator, after all violations have been reported. */
void done(T accumulator);
/**
* Report that a node violates a language feature. This doesn't have
* to throw an exception, we could also just warn, or accumulate into
* the parameter.
*/
void report(Node node, String message, T acc);
/**
* Creates a reporter that throws a {@link ParseException} when the
* first error is reported.
*/
static ReportingStrategy<Void> reporterThatThrows() {
return new ReportingStrategy<Void>() {
@Override
public Void createAccumulator() {
return null;
}
@Override
public void done(Void accumulator) {
// do nothing
}
@Override
public void report(Node node, String message, Void acc) {
throw new ParseException(
"Line " + node.getBeginLine() + ", Column " + node.getBeginColumn() + ": " + message);
}
};
}
}

View File

@ -21,6 +21,8 @@ import net.sourceforge.pmd.lang.java.JavaLanguageModule;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import net.sourceforge.pmd.lang.java.ast.MethodLikeNode;
import net.sourceforge.pmd.lang.java.ast.internal.LanguageLevelChecker;
import net.sourceforge.pmd.lang.java.ast.internal.ReportingStrategy;
import net.sourceforge.pmd.lang.java.dfa.DataFlowFacade;
import net.sourceforge.pmd.lang.java.dfa.JavaDFAGraphRule;
import net.sourceforge.pmd.lang.java.metrics.JavaMetricsComputer;
@ -46,8 +48,7 @@ import net.sf.saxon.sxpath.IndependentContext;
public class JavaLanguageHandler extends AbstractPmdLanguageVersionHandler {
private final int jdkVersion;
private final boolean preview;
private final LanguageLevelChecker<?> levelChecker;
private final LanguageMetricsProvider<ASTAnyTypeDeclaration, MethodLikeNode> myMetricsProvider = new JavaMetricsProvider();
public JavaLanguageHandler(int jdkVersion) {
@ -56,14 +57,13 @@ public class JavaLanguageHandler extends AbstractPmdLanguageVersionHandler {
public JavaLanguageHandler(int jdkVersion, boolean preview) {
super(JavaProcessingStage.class);
this.jdkVersion = jdkVersion;
this.preview = preview;
this.levelChecker = new LanguageLevelChecker<>(jdkVersion, preview, ReportingStrategy.reporterThatThrows());
}
@Override
public Parser getParser(ParserOptions parserOptions) {
return new JavaLanguageParser(jdkVersion, preview, parserOptions);
return new JavaLanguageParser(levelChecker, parserOptions);
}

View File

@ -2,7 +2,6 @@
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.internal;
import java.io.Reader;
@ -14,6 +13,7 @@ import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.JavaTokenManager;
import net.sourceforge.pmd.lang.java.ast.InternalApiBridge;
import net.sourceforge.pmd.lang.java.ast.ParseException;
import net.sourceforge.pmd.lang.java.ast.internal.LanguageLevelChecker;
/**
* Adapter for the JavaParser, using the specified grammar version.
@ -23,13 +23,11 @@ import net.sourceforge.pmd.lang.java.ast.ParseException;
*/
public class JavaLanguageParser extends AbstractParser {
private final int jdkVersion;
private final boolean preview;
private final LanguageLevelChecker<?> checker;
public JavaLanguageParser(int jdkVersion, boolean preview, ParserOptions parserOptions) {
JavaLanguageParser(LanguageLevelChecker<?> checker, ParserOptions parserOptions) {
super(parserOptions);
this.jdkVersion = jdkVersion;
this.preview = preview;
this.checker = checker;
}
@Override
@ -40,6 +38,6 @@ public class JavaLanguageParser extends AbstractParser {
@Override
public Node parse(String fileName, Reader source) throws ParseException {
return InternalApiBridge.parseInternal(fileName, source, jdkVersion, preview, getParserOptions());
return InternalApiBridge.parseInternal(fileName, source, checker, getParserOptions());
}
}

View File

@ -1,34 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.ast;
import static net.sourceforge.pmd.lang.java.ParserTstUtil.getNodes;
import org.junit.Test;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.java.JavaLanguageModule;
public class ASTAnnotationTest {
@Test
public void testAnnotationSucceedsWithDefaultMode() {
getNodes(ASTAnnotation.class, TEST1);
}
@Test(expected = ParseException.class)
public void testAnnotationFailsWithJDK14() {
getNodes(LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.4"), ASTAnnotation.class, TEST1);
}
@Test
public void testAnnotationSucceedsWithJDK15() {
getNodes(LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.5"), ASTAnnotation.class, TEST1);
}
private static final String TEST1 = "public class Foo extends Buz {" + PMD.EOL + " @Override" + PMD.EOL
+ " void bar() {" + PMD.EOL + " // overrides a superclass method" + PMD.EOL + " }" + PMD.EOL + "}";
}

View File

@ -156,7 +156,7 @@ public class ParserCornersTest {
fail("Expected exception");
} catch (ParseException e) {
assertEquals(
"Line 1, Column 94: Cannot catch multiple exceptions when running in JDK inferior to 1.7 mode!",
"Line 1, Column 70: Composite catch clauses are a feature of Java 1.7, you should select your language version accordingly",
e.getMessage());
}

View File

@ -5,6 +5,8 @@
package net.sourceforge.pmd.lang.java.ast
import net.sourceforge.pmd.lang.ast.test.shouldBe
import net.sourceforge.pmd.lang.java.ast.JavaVersion.Companion.Earliest
import net.sourceforge.pmd.lang.java.ast.JavaVersion.J1_3
import net.sourceforge.pmd.lang.java.ast.ParserTestCtx.Companion.AnnotationParsingCtx
/**
@ -13,6 +15,15 @@ import net.sourceforge.pmd.lang.java.ast.ParserTestCtx.Companion.AnnotationParsi
*/
class ASTAnnotationTest : ParserTestSpec({
parserTest("Test annot fails before JDK 1.4", javaVersions = Earliest..J1_3) {
inContext(AnnotationParsingCtx) {
"@F" shouldNot parse()
"@F(a=1)" shouldNot parse()
}
}
parserTest("Marker annotations") {
inContext(AnnotationParsingCtx) {

View File

@ -12,7 +12,7 @@ class ASTCatchStatementTest : ParserTestSpec({
parserTest("Test crash on multicatch", javaVersions = Earliest..J1_6) {
expectParseException("Cannot catch multiple exceptions when running in JDK inferior to 1.7 mode") {
expectParseException("Composite catch clauses are a feature of Java 1.7, you should select your language version accordingly") {
parseAstStatement("try { } catch (IOException | AssertionError e) { }")
}