logic: index and store Java annotations

* add annotation symbol kind
* add annotation_usage edge kind
* increment storage version
* record java annotation decls
* record java annotation member decls (as fields)
* update expected output of java sample project indexing tests
* add tests for recording annotations
* add annotation icon, annotation colors
* add new annotation node and edge types to legend
This commit is contained in:
mlangkabel
2018-08-14 17:33:00 +02:00
parent abe0248c1e
commit 9813c9873f
116 changed files with 1184 additions and 88 deletions
@@ -8,6 +8,9 @@ import java.util.Stack;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.ArrayInitializer;
import org.eclipse.jdt.core.dom.Block;
@@ -21,6 +24,7 @@ import org.eclipse.jdt.core.dom.EnumDeclaration;
import org.eclipse.jdt.core.dom.ExpressionMethodReference;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.IPackageBinding;
@@ -29,16 +33,20 @@ import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.Javadoc;
import org.eclipse.jdt.core.dom.LineComment;
import org.eclipse.jdt.core.dom.MarkerAnnotation;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.NameQualifiedType;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.QualifiedType;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
import org.eclipse.jdt.core.dom.SuperFieldAccess;
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
@@ -116,7 +124,60 @@ public abstract class AstVisitor extends ASTVisitor
return true;
}
@Override
public boolean visit(AnnotationTypeDeclaration node)
{
DeclName symbolName = DeclNameResolver.getQualifiedDeclName(node, m_filePath, m_compilationUnit);
Range scopeRange = getRange(node);
m_client.recordSymbolWithLocationAndScope(
symbolName.toNameHierarchy(),
SymbolKind.ANNOTATION,
getRange(node.getName()),
scopeRange,
AccessKind.fromModifiers(node.getModifiers()),
DefinitionKind.EXPLICIT);
scopeRange.begin = m_fileContent.findStartPosition("{", scopeRange.begin);
recordScope(scopeRange);
m_contextStack.push(Arrays.asList(symbolName));
return true;
}
@Override
public void endVisit(AnnotationTypeDeclaration node)
{
m_contextStack.pop();
}
@Override
public boolean visit(AnnotationTypeMemberDeclaration node)
{
DeclName symbolName = BindingNameResolver.getQualifiedName(node.resolveBinding(), m_filePath, m_compilationUnit).orElse(DeclName.unsolved());
m_client.recordSymbolWithLocation(
symbolName.toNameHierarchy(),
SymbolKind.FIELD,
getRange(node.getName()),
AccessKind.fromModifiers(node.getModifiers()),
DefinitionKind.EXPLICIT);
m_contextStack.push(Arrays.asList(symbolName));
return true;
}
@Override
public void endVisit(AnnotationTypeMemberDeclaration node)
{
m_contextStack.pop();
}
@Override
public boolean visit(TypeDeclaration node)
@@ -153,7 +214,8 @@ public abstract class AstVisitor extends ASTVisitor
DeclName symbolName = BindingNameResolver.getQualifiedName(node.resolveBinding(), m_filePath, m_compilationUnit).map(tn -> tn.toDeclName()).orElse(DeclName.unsolved());
m_client.recordSymbolWithLocation(
symbolName.toNameHierarchy(), SymbolKind.TYPE_PARAMETER,
symbolName.toNameHierarchy(),
SymbolKind.TYPE_PARAMETER,
getRange(node.getName()),
AccessKind.TYPE_PARAMETER,
DefinitionKind.EXPLICIT);
@@ -316,7 +378,8 @@ public abstract class AstVisitor extends ASTVisitor
DeclName symbolName = DeclNameResolver.getQualifiedDeclName(fragment, m_filePath, m_compilationUnit);
m_client.recordSymbolWithLocation(
symbolName.toNameHierarchy(), SymbolKind.FIELD,
symbolName.toNameHierarchy(),
SymbolKind.FIELD,
getRange(fragment.getName()),
AccessKind.fromModifiers(node.getModifiers()),
DefinitionKind.EXPLICIT);
@@ -389,6 +452,70 @@ public abstract class AstVisitor extends ASTVisitor
return true;
}
@Override
public boolean visit(SingleMemberAnnotation node)
{
return recordAnnotation(node);
}
@Override
public boolean visit(NormalAnnotation node)
{
for (Object value: node.values())
{
if (value instanceof MemberValuePair)
{
SimpleName name = ((MemberValuePair)value).getName();
IBinding binding = name.resolveBinding();
if (binding instanceof IMethodBinding)
{
DeclName symbolName = BindingNameResolver.getQualifiedName((IMethodBinding) binding, m_filePath, m_compilationUnit).orElse(DeclName.unsolved());
for (SymbolName context: m_contextStack.peek())
{
m_client.recordReference(ReferenceKind.USAGE, symbolName.toNameHierarchy(), context.toNameHierarchy(), getRange(name));
}
}
}
}
return recordAnnotation(node);
}
@Override
public boolean visit(MarkerAnnotation node)
{
return recordAnnotation(node);
}
private boolean recordAnnotation(Annotation node)
{
for (SymbolName context: m_contextStack.peek())
{
IAnnotationBinding annotationBinding = node.resolveAnnotationBinding();
ITypeBinding typeBinding = null;
if (annotationBinding != null)
{
typeBinding = annotationBinding.getAnnotationType();
}
Range range = getRange(node.getTypeName());
if (node.getTypeName() instanceof QualifiedName)
{
range = getRange(((QualifiedName) node.getTypeName()).getName());
}
m_client.recordReference(
ReferenceKind.ANNOTATION_USAGE,
BindingNameResolver.getQualifiedName(typeBinding, m_filePath, m_compilationUnit).orElse(TypeName.unsolved()).toDeclName().toNameHierarchy(),
context.toNameHierarchy(),
range);
}
return true;
}
@Override
public boolean visit(SimpleType node)
@@ -15,7 +15,8 @@ public enum ReferenceKind
TEMPLATE_MEMBER_SPECIALIZATION_OF(10),
INCLUDE(11),
IMPORT(12),
MACRO_USAGE(13);
MACRO_USAGE(13),
ANNOTATION_USAGE(14);
private final int m_value;
@@ -2,26 +2,27 @@ package com.sourcetrail;
public enum SymbolKind
{ // these values need to be the same as SymbolKind in C++ code
BUILTIN_TYPE(1),
CLASS(2),
ENUM(3),
ENUM_CONSTANT(4),
FIELD(5),
FUNCTION(6),
GLOBAL_VARIABLE(7),
INTERFACE(8),
LOCAL_VARIABLE(9),
MACRO(10),
METHOD(11),
NAMESPACE(12),
PACKAGE(13),
PARAMETER(14),
STRUCT(15),
TEMPLATE_PARAMETER(16),
TYPEDEF(17),
TYPE_PARAMETER(18),
UNION(19),
TYPE_MAX(20);
ANNOTATION(1),
BUILTIN_TYPE(2),
CLASS(3),
ENUM(4),
ENUM_CONSTANT(5),
FIELD(6),
FUNCTION(7),
GLOBAL_VARIABLE(8),
INTERFACE(9),
LOCAL_VARIABLE(10),
MACRO(11),
METHOD(12),
NAMESPACE(13),
PACKAGE(14),
PARAMETER(15),
STRUCT(16),
TEMPLATE_PARAMETER(17),
TYPEDEF(18),
TYPE_PARAMETER(19),
UNION(20),
TYPE_MAX(21);
private final int m_value;
@@ -200,21 +200,31 @@ public class BindingNameResolver extends NameResolver
}
}
ContextList ignoredContexts = m_ignoredContexts.copy();
ignoredContexts.add(binding);
TypeName returnTypeName = binding.isConstructor() ? null : getQualifiedName(binding.getReturnType(), m_currentFile, m_compilationUnit, ignoredContexts).orElse(TypeName.unsolved());
List<TypeName> parameterTypeNames = new ArrayList<>();
for (ITypeBinding parameterType: binding.getParameterTypes())
DeclName declName = null;
{
parameterTypeNames.add(getQualifiedName(parameterType, m_currentFile, m_compilationUnit, ignoredContexts).orElse(TypeName.unsolved()));
boolean isStatic = Modifier.isStatic(binding.getModifiers());
ContextList ignoredContexts = m_ignoredContexts.copy();
ignoredContexts.add(binding);
TypeName returnTypeName = binding.isConstructor() ? null : getQualifiedName(binding.getReturnType(), m_currentFile, m_compilationUnit, ignoredContexts).orElse(TypeName.unsolved());
if (binding.isAnnotationMember())
{
declName = new VariableDeclName(name, returnTypeName, isStatic);
}
else
{
List<TypeName> parameterTypeNames = new ArrayList<>();
for (ITypeBinding parameterType: binding.getParameterTypes())
{
parameterTypeNames.add(getQualifiedName(parameterType, m_currentFile, m_compilationUnit, ignoredContexts).orElse(TypeName.unsolved()));
}
declName = new FunctionDeclName(name, typeParameterNames, returnTypeName, parameterTypeNames, isStatic);
}
}
boolean isStatic = Modifier.isStatic(binding.getModifiers());
FunctionDeclName declName = new FunctionDeclName(name, typeParameterNames, returnTypeName, parameterTypeNames, isStatic);
DeclName parentDeclName = getQualifiedContextName(binding);
if (parentDeclName != null)
{
@@ -151,7 +151,7 @@ public class DeclNameResolver extends NameResolver
{
if (decl instanceof AnnotationTypeDeclaration)
{
declName = new DeclName("AnnotationTypeDeclaration");
declName = new DeclName(((AnnotationTypeDeclaration) decl).getName().getIdentifier());
}
else if (decl instanceof EnumDeclaration)
{
@@ -174,7 +174,7 @@ public class DeclNameResolver extends NameResolver
}
else if (decl instanceof AnnotationTypeMemberDeclaration)
{
declName = new DeclName("AnnotationTypeMemberDeclaration");
declName = new DeclName(((AnnotationTypeMemberDeclaration) decl).getName().getIdentifier());
}
else if (decl instanceof EnumConstantDeclaration)
{