Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fix Problems with javadoc parameters @exception and others #3035

Merged
merged 6 commits into from
Jun 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 9 additions & 46 deletions src/main/java/spoon/javadoc/internal/JavadocBlockTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*/
package spoon.javadoc.internal;

import spoon.reflect.code.CtJavaDocTag;

import java.io.Serializable;

/**
Expand All @@ -24,68 +26,29 @@
*/
public class JavadocBlockTag implements Serializable {

/**
* The type of tag: it could either correspond to a known tag (param, return, etc.) or represent
* an unknown tag.
*/
public enum Type {
AUTHOR,
DEPRECATED,
EXCEPTION,
PARAM,
RETURN,
SEE,
SERIAL,
SERIAL_DATA,
SERIAL_FIELD,
SINCE,
THROWS,
VERSION,
UNKNOWN;

Type() {
this.keyword = name();
}

private String keyword;

boolean hasName() {
return this == PARAM || this == THROWS;
}

static Type fromName(String tagName) {
for (Type t : Type.values()) {
if (t.keyword.toUpperCase().equals(tagName.toUpperCase())) {
return t;
}
}
return UNKNOWN;
}
}

private Type type;
private CtJavaDocTag.TagType type;
private JavadocDescription content;
private String name = "";
private String tagName;

public JavadocBlockTag(Type type, String content) {
public JavadocBlockTag(CtJavaDocTag.TagType type, String content) {
this.type = type;
this.tagName = type.keyword;
this.tagName = type.getName();
this.content = Javadoc.parseText(content);
}

public JavadocBlockTag(String tagName, String content) {
this(Type.fromName(tagName), content);
this(CtJavaDocTag.TagType.tagFromName(tagName), content);
this.tagName = tagName;
}

public JavadocBlockTag(String tagName, String paramName, String content) {
this(Type.fromName(tagName), content);
this(CtJavaDocTag.TagType.tagFromName(tagName), content);
this.tagName = tagName;
this.name = paramName;
}

public Type getType() {
public CtJavaDocTag.TagType getType() {
return type;
}

Expand Down Expand Up @@ -154,4 +117,4 @@ public String toString() {
+ name
+ '}';
}
}
}
53 changes: 33 additions & 20 deletions src/main/java/spoon/reflect/code/CtJavaDocTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import spoon.reflect.annotations.PropertyGetter;
import spoon.reflect.annotations.PropertySetter;

import java.util.Arrays;

import static spoon.reflect.path.CtRole.COMMENT_CONTENT;
import static spoon.reflect.path.CtRole.JAVADOC_TAG_VALUE;
import static spoon.reflect.path.CtRole.DOCUMENTATION_TYPE;
Expand All @@ -32,26 +34,40 @@ public interface CtJavaDocTag extends CtElement {
* Define the possible type for a tag
*/
enum TagType {
AUTHOR,
DEPRECATED,
EXCEPTION,
PARAM,
RETURN,
SEE,
SERIAL,
SERIAL_DATA,
SERIAL_FIELD,
SINCE,
THROWS,
VERSION,
UNKNOWN;
AUTHOR("author"),
DEPRECATED("deprecated"),
EXCEPTION("exception"),
PARAM("param"),
RETURN("return"),
SEE("see"),
SERIAL("serial"),
SERIAL_DATA("serialData"),
SERIAL_FIELD("serialField"),
SINCE("since"),
THROWS("throws"),
VERSION("version"),
UNKNOWN("unknown");

TagType(String name) {
this.name = name;
}

private String name;

/**
* Get tag name
* @return name
*/
public String getName() {
return name;
}

/**
* Return true if the tag can have a parameter
* @return true if the tag can have a parameter
*/
public boolean hasParam() {
return this == PARAM || this == THROWS;
return this == PARAM || this == THROWS || this == EXCEPTION;
}

/**
Expand All @@ -60,12 +76,9 @@ public boolean hasParam() {
* @return the tag type
*/
public static TagType tagFromName(String tagName) {
for (TagType t : TagType.values()) {
if (t.name().toLowerCase().equals(tagName.toLowerCase())) {
return t;
}
}
return UNKNOWN;
return Arrays.stream(TagType.values())
.filter(v -> v.name.equals(tagName))
.findFirst().orElse(UNKNOWN);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@


import java.lang.annotation.Annotation;

import spoon.reflect.code.BinaryOperatorKind;
import spoon.reflect.code.CtAbstractInvocation;
import spoon.reflect.code.CtArrayAccess;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
public class CtJavaDocTagImpl extends CtElementImpl implements CtJavaDocTag {

@MetamodelPropertyField(role = DOCUMENTATION_TYPE)
private CtJavaDocTag.TagType type;
private TagType type;
@MetamodelPropertyField(role = COMMENT_CONTENT)
private String content;
@MetamodelPropertyField(role = JAVADOC_TAG_VALUE)
Expand All @@ -30,7 +30,7 @@ public TagType getType() {

@Override
public <E extends CtJavaDocTag> E setType(String type) {
this.setType(CtJavaDocTag.TagType.tagFromName(type));
this.setType(TagType.tagFromName(type));
return (E) this;
}

Expand Down
53 changes: 51 additions & 2 deletions src/test/java/spoon/test/javadoc/JavaDocTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,24 @@
import spoon.Launcher;
import spoon.OutputType;
import spoon.SpoonAPI;
import spoon.javadoc.internal.JavadocDescriptionElement;
import spoon.javadoc.internal.JavadocInlineTag;
import spoon.reflect.CtModel;
import spoon.reflect.code.CtComment;
import spoon.reflect.code.CtJavaDoc;
import spoon.reflect.code.CtJavaDocTag;
import spoon.reflect.code.CtJavaDocTag.TagType;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtEnum;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtType;
import spoon.reflect.factory.Factory;
import spoon.reflect.visitor.CtScanner;
import spoon.support.reflect.code.CtJavaDocImpl;
import spoon.reflect.visitor.filter.TypeFilter;
import spoon.test.javadoc.testclasses.Bar;

import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static spoon.testing.utils.Check.assertCtElementEquals;
Expand Down Expand Up @@ -132,4 +138,47 @@ public void testBugSetContent() {
assertEquals("foo", j.getTags().get(0).getContent());
}

@Test
public void testTagsParameters() {
// contract: @throws and @exception should have proper params
Launcher launcher = new Launcher();
launcher.addInputResource("./src/test/java/spoon/test/javadoc/testclasses/A.java");
launcher.getEnvironment().setCommentEnabled(true);
launcher.getEnvironment().setNoClasspath(true);
CtModel model = launcher.buildModel();

List<CtJavaDoc> javadocs = model.getElements(new TypeFilter<>(CtJavaDoc.class));

CtJavaDocTag throwsTag = javadocs.get(0).getTags().get(0);
CtJavaDocTag exceptionTag = javadocs.get(1).getTags().get(0);

assertEquals("IllegalArgumentException", throwsTag.getParam());
assertEquals("FileNotFoundException", exceptionTag.getParam());
}

@Test
public void testJavadocTagNames() {
//contract: we should handle all possible javadoc tags properly
Launcher launcher = new Launcher();
launcher.addInputResource("./src/test/java/spoon/test/javadoc/testclasses/B.java");
launcher.getEnvironment().setCommentEnabled(true);
launcher.getEnvironment().setNoClasspath(true);
CtModel model = launcher.buildModel();

CtType<?> type = model.getAllTypes().stream().findFirst().get();
assertEquals(TagType.VERSION, type.getElements(new TypeFilter<>(CtEnum.class)).get(0).getElements(new TypeFilter<>(CtJavaDoc.class)).get(0).getTags().get(0).getType());
assertEquals(TagType.AUTHOR, type.getMethodsByName("m1").get(0).getElements(new TypeFilter<>(CtJavaDoc.class)).get(0).getTags().get(0).getType());
assertEquals(TagType.DEPRECATED, type.getMethodsByName("m2").get(0).getElements(new TypeFilter<>(CtJavaDoc.class)).get(0).getTags().get(0).getType());
assertEquals(TagType.EXCEPTION, type.getMethodsByName("m3").get(0).getElements(new TypeFilter<>(CtJavaDoc.class)).get(0).getTags().get(0).getType());
assertEquals(TagType.PARAM, type.getMethodsByName("m4").get(0).getElements(new TypeFilter<>(CtJavaDoc.class)).get(0).getTags().get(0).getType());
assertEquals(TagType.RETURN, type.getMethodsByName("m5").get(0).getElements(new TypeFilter<>(CtJavaDoc.class)).get(0).getTags().get(0).getType());
assertEquals(TagType.SEE, type.getMethodsByName("m6").get(0).getElements(new TypeFilter<>(CtJavaDoc.class)).get(0).getTags().get(0).getType());
assertEquals(TagType.SERIAL, type.getField("m7").getElements(new TypeFilter<>(CtJavaDoc.class)).get(0).getTags().get(0).getType());
assertEquals(TagType.SERIAL_DATA, type.getMethodsByName("m8").get(0).getElements(new TypeFilter<>(CtJavaDoc.class)).get(0).getTags().get(0).getType());
assertEquals(TagType.SERIAL_FIELD, type.getField("m9").getElements(new TypeFilter<>(CtJavaDoc.class)).get(0).getTags().get(0).getType());
assertEquals(TagType.SINCE, type.getMethodsByName("m10").get(0).getElements(new TypeFilter<>(CtJavaDoc.class)).get(0).getTags().get(0).getType());
assertEquals(TagType.THROWS, type.getMethodsByName("m11").get(0).getElements(new TypeFilter<>(CtJavaDoc.class)).get(0).getTags().get(0).getType());
assertEquals(TagType.UNKNOWN, type.getMethodsByName("m12").get(0).getElements(new TypeFilter<>(CtJavaDoc.class)).get(0).getTags().get(0).getType());
}

}
20 changes: 20 additions & 0 deletions src/test/java/spoon/test/javadoc/testclasses/A.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package spoon.test.javadoc.testclasses;

import java.io.FileNotFoundException;

public class A {

/**
* @throws IllegalArgumentException if ....
*/
void m1() {

}

/**
* @exception FileNotFoundException if ....
*/
void m2() {

}
}
69 changes: 69 additions & 0 deletions src/test/java/spoon/test/javadoc/testclasses/B.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package spoon.test.javadoc.testclasses;

public class B {

/**
* @version 42
*/
enum Something { ONE, TWO, THREE }

/**
* @author somebody
*/
void m1() {}

/**
* @deprecated
*/
void m2() {}

/**
* @exception RuntimeException if ...
*/
void m3() {}

/**
* @param a ...
*/
void m4(int a) {}

/**
* @return 42
*/
int m5() { return 42; }

/**
* @see B
*/
void m6() {}

/**
* @serial description
*/
int m7;

/**
* @serialData description
*/
void m8() {}

/**
* @serialField description
*/
int m9;

/**
* @since 42
*/
void m10() {}

/**
* @throws RuntimeException if ...
*/
void m11() {}

/**
* @somethingInconsistent ...
*/
void m12() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
import spoon.reflect.code.CtJavaDocTag;
import spoon.reflect.cu.CompilationUnit;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtCodeSnippet;
import spoon.reflect.declaration.CtInterface;
import spoon.reflect.declaration.ModifierKind;
import spoon.support.modelobs.ActionBasedChangeListenerImpl;
import spoon.support.modelobs.action.Action;
Expand Down