Skip to content

Commit

Permalink
Java ApiView: Add context to annotation id (#5426)
Browse files Browse the repository at this point in the history
* Add context to annotation id

* check for null

* pr comment
  • Loading branch information
srnagar authored Feb 13, 2023
1 parent 30dd44f commit c806a96
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1031,7 +1031,7 @@ private void getAnnotations(final NodeWithAnnotations<?> nodeWithAnnotations,
addToken(makeWhitespace());
}

addToken(new Token(TYPE_NAME, "@" + annotation.getName().toString(), makeId(annotation)));
addToken(new Token(TYPE_NAME, "@" + annotation.getName().toString(), makeId(annotation, nodeWithAnnotations)));
if (showAnnotationProperties) {
if (annotation instanceof NormalAnnotationExpr) {
addToken(new Token(PUNCTUATION, "("));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@
import com.github.javaparser.ast.body.CallableDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.ConstructorDeclaration;
import com.github.javaparser.ast.body.EnumConstantDeclaration;
import com.github.javaparser.ast.body.EnumDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.TypeDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.comments.Comment;
import com.github.javaparser.ast.comments.JavadocComment;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.nodeTypes.NodeWithAnnotations;
import com.github.javaparser.ast.nodeTypes.NodeWithJavadoc;

import java.util.Collections;
Expand Down Expand Up @@ -197,9 +200,43 @@ public static String makeId(String fullPath) {
return MAKE_ID.matcher(fullPath).replaceAll("-");
}

public static String makeId(AnnotationExpr annotation) {
int line = annotation.getBegin().orElseThrow(RuntimeException::new).line;
return makeId(getNodeFullyQualifiedName(annotation.getParentNode()) + "." + annotation.getNameAsString() + "-L" + line);
public static String makeId(AnnotationExpr annotation, NodeWithAnnotations<?> nodeWithAnnotations) {
String annotationContext = getAnnotationContext(nodeWithAnnotations);

String idSuffix;

if (annotationContext == null || annotationContext.isEmpty()) {
idSuffix = "-L" + annotation.getBegin().orElseThrow(RuntimeException::new).line;
} else {
idSuffix = "-" + annotationContext;
}
return makeId(getNodeFullyQualifiedName(annotation.getParentNode()) + "." + annotation.getNameAsString() + idSuffix);
}

private static String getAnnotationContext(NodeWithAnnotations<?> nodeWithAnnotations) {
if (nodeWithAnnotations == null) {
return "";
}
if (nodeWithAnnotations instanceof MethodDeclaration) {
MethodDeclaration methodDeclaration = (MethodDeclaration) nodeWithAnnotations;
// use the method declaration string instead of method name as there can be overloads
return methodDeclaration.getDeclarationAsString(true, true, true);
} else if (nodeWithAnnotations instanceof ClassOrInterfaceDeclaration) {
ClassOrInterfaceDeclaration classOrInterfaceDeclaration = (ClassOrInterfaceDeclaration) nodeWithAnnotations;
return classOrInterfaceDeclaration.getNameAsString();
} else if (nodeWithAnnotations instanceof EnumDeclaration) {
EnumDeclaration enumDeclaration = (EnumDeclaration) nodeWithAnnotations;
return enumDeclaration.getNameAsString();
} else if (nodeWithAnnotations instanceof EnumConstantDeclaration) {
EnumConstantDeclaration enumValueDeclaration = (EnumConstantDeclaration) nodeWithAnnotations;
return enumValueDeclaration.getNameAsString();
} else if (nodeWithAnnotations instanceof ConstructorDeclaration) {
ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) nodeWithAnnotations;
// use the constructor declaration string instead of the name as there can be overloads
return constructorDeclaration.getDeclarationAsString(true, true, true);
} else {
return "";
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
import com.azure.tools.apiview.processor.model.Diagnostic;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.nodeTypes.NodeWithAnnotations;

import java.util.*;
import java.util.function.Consumer;

import static com.azure.tools.apiview.processor.analysers.util.ASTUtils.*;
import static com.azure.tools.apiview.processor.model.DiagnosticKind.WARNING;
Expand All @@ -18,32 +18,44 @@
*/
public class BadAnnotationDiagnosticRule implements DiagnosticRule {

private List<BadAnnotation> badAnnotations;
private final List<BadAnnotation> badAnnotations;

public BadAnnotationDiagnosticRule(BadAnnotation... badAnnotations) {
this.badAnnotations = Arrays.asList(badAnnotations);
}

@Override
public void scanIndividual(final CompilationUnit cu, final APIListing listing) {
Consumer<AnnotationExpr> annotationConsumer = a -> {
badAnnotations.forEach(badAnnotation -> {
// check if the badAnnotation is the same as the found annotation
if (badAnnotation.annotation.equals(a.getNameAsString())) {
// we've got a match - file it as a diagnostic
listing.addDiagnostic(new Diagnostic(WARNING, makeId(a), badAnnotation.errorMessage));
}
});
};

getClasses(cu).forEach(typeDeclaration -> {
// check annotations on the type itself
typeDeclaration.getAnnotations().stream().forEach(annotationConsumer);
typeDeclaration.getAnnotations()
.forEach(annotation -> checkForBadAnnotations(listing, typeDeclaration, annotation));

// check annotations on fields, constructors, methods
getPublicOrProtectedFields(typeDeclaration).flatMap(method -> method.getAnnotations().stream()).forEach(annotationConsumer);
getPublicOrProtectedConstructors(typeDeclaration).flatMap(method -> method.getAnnotations().stream()).forEach(annotationConsumer);
getPublicOrProtectedMethods(typeDeclaration).flatMap(method -> method.getAnnotations().stream()).forEach(annotationConsumer);
// check annotations on fields
getPublicOrProtectedFields(typeDeclaration)
.forEach(field -> field.getAnnotations()
.forEach(annotation -> checkForBadAnnotations(listing, field, annotation)));

// check annotations on constructors
getPublicOrProtectedConstructors(typeDeclaration)
.forEach(constructor -> constructor.getAnnotations()
.forEach(annotation -> checkForBadAnnotations(listing, constructor, annotation)));
// check annotations on methods
getPublicOrProtectedMethods(typeDeclaration)
.forEach(method -> method.getAnnotations()
.forEach(annotation -> checkForBadAnnotations(listing, method, annotation)));
});
}

private void checkForBadAnnotations(APIListing listing, NodeWithAnnotations<?> nodeWithAnnotations, AnnotationExpr annotation) {
badAnnotations.forEach(badAnnotation -> {
// check if the badAnnotation is the same as the found annotation
if (badAnnotation.annotation.equals(annotation.getNameAsString())) {
// we've got a match - file it as a diagnostic
listing.addDiagnostic(new Diagnostic(WARNING, makeId(annotation, nodeWithAnnotations),
badAnnotation.errorMessage));
}
});
}

Expand Down

0 comments on commit c806a96

Please sign in to comment.