in src/java/apiview-java-processor/src/main/java/com/azure/tools/apiview/processor/analysers/JavaASTAnalyser.java [598:765]
private void visitDefinition(BodyDeclaration<?> definition, ReviewLine parentLine) {
boolean isTypeDeclaration = false;
String id;
String name;
if (definition instanceof TypeDeclaration<?>) {
TypeDeclaration<?> typeDeclaration = (TypeDeclaration<?>) definition;
// Skip if the class is private or package-private, unless it is a nested type defined inside a public interface
if (!isTypeAPublicAPI(typeDeclaration)) {
return;
}
// FIXME getKnownTypes is...icky
id = makeId(typeDeclaration);
name = typeDeclaration.getNameAsString();
apiListing.getKnownTypes().put(typeDeclaration.getFullyQualifiedName().orElse(""), id);
isTypeDeclaration = true;
} else if (definition instanceof FieldDeclaration) {
FieldDeclaration fieldDeclaration = (FieldDeclaration) definition;
id = makeId(fieldDeclaration);
name = fieldDeclaration.toString();
} else if (definition instanceof CallableDeclaration<?>) {
CallableDeclaration<?> callableDeclaration = (CallableDeclaration<?>) definition;
id = makeId(callableDeclaration);
name = callableDeclaration.getNameAsString();
} else {
System.out.println("Unknown definition type: " + definition.getClass().getName());
System.exit(-1);
return;
}
// when we are dealing with a type declaration, annotations go on the line *before* the definition,
// as opposed to fields and methods where they go on the same line
final boolean showAnnotationsOnNewLine = isTypeDeclaration;
final ReviewLine definitionLine;
if (isTypeDeclaration) {
visitAnnotations(definition, isTypeDeclaration, showAnnotationsOnNewLine, parentLine, id);
visitJavaDoc(definition, parentLine, id);
definitionLine = parentLine.addChildLine(new ReviewLine(parentLine, id));
} else {
visitJavaDoc(definition, parentLine, id);
definitionLine = parentLine.addChildLine(new ReviewLine(parentLine, id));
visitAnnotations(definition, isTypeDeclaration, showAnnotationsOnNewLine, definitionLine, definitionLine);
}
// Add modifiers - public, protected, static, final, etc
for (final Modifier modifier : ((NodeWithModifiers<?>)definition).getModifiers()) {
definitionLine.addToken(new ReviewToken(KEYWORD, modifier.getKeyword().asString()));
}
// for type declarations, add in if it is a class, annotation, enum, interface, etc
if (definition instanceof TypeDeclaration<?>) {
TypeDeclaration<?> typeDeclaration = (TypeDeclaration<?>) definition;
TokenKind kind = getTokenKind(typeDeclaration);
definitionLine.addToken(new ReviewToken(KEYWORD, kind.getTypeDeclarationString()));
// Note that it is not necessary to specify the ID here, as it is already specified on the TreeNode
ReviewToken typeNameToken = new ReviewToken(kind, name)
.setSpacing(Spacing.NO_SPACE); // no space here - we have to see if there is any type parameters below first
typeNameToken.setNavigationDisplayName(name);
possiblyAddNavigationLink(typeNameToken, typeDeclaration);
possiblyDeprecate(typeNameToken, typeDeclaration);
checkForCrossLanguageDefinitionId(definitionLine, typeDeclaration);
definitionLine.addToken(typeNameToken);
}
boolean addedSpace = false;
// Add type parameters for definition
if (definition instanceof NodeWithTypeParameters<?>) {
NodeWithTypeParameters<?> d = (NodeWithTypeParameters<?>) definition;
spacingState = SpacingState.SKIP_NEXT_SUFFIX;
boolean modified = visitTypeParameters(d.getTypeParameters(), definitionLine);
spacingState = SpacingState.DEFAULT;
if (modified) {
// add the space we skipped earlier, due to the generics
definitionLine.addSpace();
addedSpace = true;
}
}
if (!addedSpace && definition instanceof TypeDeclaration<?>) {
// add the space we skipped earlier, due to the generics
definitionLine.addSpace();
}
// Add type for definition - this is the return type for methods
visitType(definition, definitionLine, RETURN_TYPE);
if (definition instanceof FieldDeclaration) {
// For Fields - we add the field type and name
visitDeclarationNameAndVariables((FieldDeclaration) definition, definitionLine);
definitionLine.addToken(new ReviewToken(PUNCTUATION, ";"));
} else if (definition instanceof CallableDeclaration<?>) {
// For Methods - Add name and parameters for definition
CallableDeclaration<?> n = (CallableDeclaration<?>) definition;
visitDeclarationNameAndParameters(n, n.getParameters(), definitionLine);
// Add throw exceptions for definition
visitThrowException(n, definitionLine);
} else if (definition instanceof TypeDeclaration<?>) {
TypeDeclaration<?> d = (TypeDeclaration<?>) definition;
// add in types that we are extending or implementing
visitExtendsAndImplements((TypeDeclaration<?>) definition, definitionLine);
definitionLine.addContextStartTokens();
// now process inner values (e.g. if it is a class, interface, enum, etc
if (d.isEnumDeclaration()) {
visitEnumEntries((EnumDeclaration) d, definitionLine);
}
// Get if the declaration is interface or not
boolean isInterfaceDeclaration = isInterfaceType(d);
// public custom annotation @interface's members
if (d.isAnnotationDeclaration() && isPublicOrProtected(d.getAccessSpecifier())) {
final AnnotationDeclaration annotationDeclaration = (AnnotationDeclaration) d;
visitAnnotationMember(annotationDeclaration, definitionLine);
}
// get fields
visitFields(isInterfaceDeclaration, d, definitionLine);
// get Constructors
final List<ConstructorDeclaration> constructors = d.getConstructors();
if (constructors.isEmpty()) {
// add default constructor if there is no constructor at all, except interface and enum
if (!isInterfaceDeclaration && !d.isEnumDeclaration() && !d.isAnnotationDeclaration()) {
addDefaultConstructor(d, definitionLine);
} else {
// skip and do nothing if there is no constructor in the interface.
}
} else {
visitConstructorsOrMethods(d, isInterfaceDeclaration, true, constructors, definitionLine);
}
// get Methods
visitConstructorsOrMethods(d, isInterfaceDeclaration, false, d.getMethods(), definitionLine);
// get Inner classes
d.getChildNodes()
.stream()
.filter(n -> n instanceof TypeDeclaration)
.map(n -> (TypeDeclaration<?>) n)
.forEach(innerType -> {
if (innerType.isEnumDeclaration() || innerType.isClassOrInterfaceDeclaration()) {
visitDefinition(innerType, definitionLine);
}
});
if (isInterfaceDeclaration) {
if (d.getMembers().isEmpty()) {
// we have an empty interface declaration, it is probably a marker interface and we will leave a
// comment to that effect
definitionLine.addChildLine().addToken(COMMENT, "// This interface does not declare any API.");
}
}
definitionLine.addContextEndTokens();
}
}