* added some more tests * changed 3rd party licenses respectively fortune cookie message = Your present plans are going to succeed.
749 lines
20 KiB
Java
749 lines
20 KiB
Java
package com.sourcetrail;
|
|
|
|
import java.io.File;
|
|
import java.lang.String;
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
import java.util.Stack;
|
|
|
|
import org.eclipse.jdt.core.dom.ASTNode;
|
|
import org.eclipse.jdt.core.dom.ASTVisitor;
|
|
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
|
|
import org.eclipse.jdt.core.dom.ArrayInitializer;
|
|
import org.eclipse.jdt.core.dom.Block;
|
|
import org.eclipse.jdt.core.dom.BlockComment;
|
|
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
|
|
import org.eclipse.jdt.core.dom.CompilationUnit;
|
|
import org.eclipse.jdt.core.dom.ConstructorInvocation;
|
|
import org.eclipse.jdt.core.dom.CreationReference;
|
|
import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
|
|
import org.eclipse.jdt.core.dom.EnumDeclaration;
|
|
import org.eclipse.jdt.core.dom.ExpressionMethodReference;
|
|
import org.eclipse.jdt.core.dom.FieldDeclaration;
|
|
import org.eclipse.jdt.core.dom.IBinding;
|
|
import org.eclipse.jdt.core.dom.IMethodBinding;
|
|
import org.eclipse.jdt.core.dom.IPackageBinding;
|
|
import org.eclipse.jdt.core.dom.ITypeBinding;
|
|
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.MethodDeclaration;
|
|
import org.eclipse.jdt.core.dom.MethodInvocation;
|
|
import org.eclipse.jdt.core.dom.NameQualifiedType;
|
|
import org.eclipse.jdt.core.dom.PackageDeclaration;
|
|
import org.eclipse.jdt.core.dom.PrimitiveType;
|
|
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.SuperConstructorInvocation;
|
|
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
|
|
import org.eclipse.jdt.core.dom.SuperMethodReference;
|
|
import org.eclipse.jdt.core.dom.SwitchStatement;
|
|
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
|
import org.eclipse.jdt.core.dom.TypeMethodReference;
|
|
import org.eclipse.jdt.core.dom.TypeParameter;
|
|
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
|
|
|
|
import com.sourcetrail.name.JavaDeclName;
|
|
import com.sourcetrail.name.JavaFileName;
|
|
import com.sourcetrail.name.JavaSymbolName;
|
|
import com.sourcetrail.name.JavaTypeName;
|
|
import com.sourcetrail.name.NameHierarchy;
|
|
import com.sourcetrail.name.resolver.BindingNameResolver;
|
|
import com.sourcetrail.name.resolver.DeclNameResolver;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
|
|
public abstract class AstVisitor extends ASTVisitor
|
|
{
|
|
protected AstVisitorClient m_client = null;
|
|
private File m_filePath;
|
|
private FileContent m_fileContent = null;
|
|
private CompilationUnit m_compilationUnit;
|
|
private Stack<List<JavaSymbolName>> m_contextStack = new Stack<>();
|
|
|
|
public AstVisitor(AstVisitorClient client, File filePath, String fileContent, CompilationUnit compilationUnit)
|
|
{
|
|
m_client = client;
|
|
m_filePath = filePath;
|
|
m_fileContent = new FileContent(fileContent);
|
|
m_compilationUnit = compilationUnit;
|
|
|
|
m_contextStack.push(Arrays.asList(new JavaFileName(filePath)));
|
|
}
|
|
|
|
protected abstract ReferenceKind getTypeReferenceKind();
|
|
|
|
|
|
// --- record declarations ---
|
|
|
|
@Override
|
|
public boolean visit(PackageDeclaration node)
|
|
{
|
|
m_client.recordSymbolWithLocation(
|
|
DeclNameResolver.getQualifiedName(node.getName()).toNameHierarchy(),
|
|
SymbolKind.PACKAGE,
|
|
getRange(node.getName()),
|
|
AccessKind.NONE,
|
|
DefinitionKind.EXPLICIT);
|
|
return true;
|
|
}
|
|
|
|
|
|
@Override
|
|
public boolean visit(TypeDeclaration node)
|
|
{
|
|
JavaDeclName symbolName = DeclNameResolver.getQualifiedDeclName(node, m_filePath, m_compilationUnit);
|
|
Range scopeRange = getRange(node);
|
|
|
|
m_client.recordSymbolWithLocationAndScope(
|
|
symbolName.toNameHierarchy(),
|
|
node.isInterface() ? SymbolKind.INTERFACE : SymbolKind.CLASS,
|
|
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(TypeDeclaration node)
|
|
{
|
|
m_contextStack.pop();
|
|
}
|
|
|
|
|
|
@Override
|
|
public boolean visit(TypeParameter node)
|
|
{
|
|
JavaDeclName symbolName = BindingNameResolver.getQualifiedName(node.resolveBinding(), m_filePath, m_compilationUnit).map(tn -> tn.toDeclName()).orElse(JavaDeclName.unsolved());
|
|
|
|
m_client.recordSymbolWithLocation(
|
|
symbolName.toNameHierarchy(), SymbolKind.TYPE_PARAMETER,
|
|
getRange(node.getName()),
|
|
AccessKind.TYPE_PARAMETER,
|
|
DefinitionKind.EXPLICIT);
|
|
|
|
m_contextStack.push(Arrays.asList(symbolName));
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void endVisit(TypeParameter node)
|
|
{
|
|
m_contextStack.pop();
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
public boolean visit(EnumDeclaration node)
|
|
{
|
|
JavaDeclName symbolName = DeclNameResolver.getQualifiedDeclName(node, m_filePath, m_compilationUnit);
|
|
Range scopeRange = getRange(node);
|
|
|
|
m_client.recordSymbolWithLocationAndScope(
|
|
symbolName.toNameHierarchy(),
|
|
SymbolKind.ENUM,
|
|
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(EnumDeclaration node)
|
|
{
|
|
m_contextStack.pop();
|
|
}
|
|
|
|
|
|
public boolean visit(EnumConstantDeclaration node)
|
|
{
|
|
JavaDeclName symbolName = DeclNameResolver.getQualifiedDeclName(node, m_filePath, m_compilationUnit);
|
|
|
|
m_client.recordSymbolWithLocation(
|
|
symbolName.toNameHierarchy(),
|
|
SymbolKind.ENUM_CONSTANT,
|
|
getRange(node.getName()),
|
|
AccessKind.NONE,
|
|
DefinitionKind.EXPLICIT);
|
|
|
|
m_contextStack.push(Arrays.asList(symbolName));
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void endVisit(EnumConstantDeclaration node)
|
|
{
|
|
m_contextStack.pop();
|
|
}
|
|
|
|
|
|
@Override
|
|
public boolean visit(MethodDeclaration node)
|
|
{
|
|
if (m_client.getInterrupted())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
JavaDeclName symbolName = DeclNameResolver.getQualifiedDeclName(node, m_filePath, m_compilationUnit);
|
|
|
|
m_client.recordSymbolWithLocationAndScope(
|
|
symbolName.toNameHierarchy(),
|
|
SymbolKind.METHOD,
|
|
getRange(node.getName()),
|
|
getRange(node),
|
|
AccessKind.fromModifiers(node.getModifiers()),
|
|
DefinitionKind.EXPLICIT);
|
|
|
|
|
|
Optional<IMethodBinding> overriddenMethod = getOverriddenMethod(node.resolveBinding());
|
|
if (overriddenMethod.isPresent())
|
|
{
|
|
// We use the declaration to replace type arguments with the respective type parameters inside the signature.
|
|
IMethodBinding overriddenMethodDeclaration = overriddenMethod.get().getMethodDeclaration();
|
|
|
|
JavaDeclName overriddenMethodName = BindingNameResolver.getQualifiedName(overriddenMethodDeclaration, m_filePath, m_compilationUnit).orElse(JavaDeclName.unsolved());
|
|
if (!overriddenMethodName.getIsUnsolved())
|
|
{
|
|
m_client.recordSymbol(overriddenMethodName.toNameHierarchy(), SymbolKind.METHOD, AccessKind.NONE, DefinitionKind.NONE);
|
|
}
|
|
|
|
m_client.recordReference(
|
|
ReferenceKind.OVERRIDE,
|
|
overriddenMethodName.toNameHierarchy(),
|
|
symbolName.toNameHierarchy(),
|
|
getRange(node.getName()));
|
|
}
|
|
|
|
m_contextStack.push(Arrays.asList(symbolName));
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void endVisit(MethodDeclaration node)
|
|
{
|
|
m_contextStack.pop();
|
|
}
|
|
|
|
|
|
@Override
|
|
public boolean visit(FieldDeclaration node)
|
|
{
|
|
ArrayList<JavaSymbolName> childContext = new ArrayList<>();
|
|
|
|
for (Object declarator: node.fragments())
|
|
{
|
|
if (declarator instanceof VariableDeclarationFragment)
|
|
{
|
|
VariableDeclarationFragment fragment = (VariableDeclarationFragment) declarator;
|
|
|
|
JavaDeclName symbolName = DeclNameResolver.getQualifiedDeclName(fragment, m_filePath, m_compilationUnit);
|
|
|
|
m_client.recordSymbolWithLocation(
|
|
symbolName.toNameHierarchy(), SymbolKind.FIELD,
|
|
getRange(fragment.getName()),
|
|
AccessKind.fromModifiers(node.getModifiers()),
|
|
DefinitionKind.EXPLICIT);
|
|
|
|
childContext.add(symbolName);
|
|
}
|
|
}
|
|
|
|
m_contextStack.push(childContext);
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void endVisit(FieldDeclaration node)
|
|
{
|
|
m_contextStack.pop();
|
|
}
|
|
|
|
|
|
// --- record references ---
|
|
|
|
@Override
|
|
public boolean visit(final ImportDeclaration node)
|
|
{
|
|
JavaDeclName symbolName = JavaDeclName.unsolved();
|
|
IBinding binding = node.resolveBinding();
|
|
if (!binding.isRecovered())
|
|
{
|
|
if (binding instanceof IPackageBinding)
|
|
{
|
|
symbolName = BindingNameResolver.getQualifiedName((IPackageBinding) binding, m_filePath, m_compilationUnit).orElse(JavaDeclName.unsolved());
|
|
}
|
|
else if (binding instanceof ITypeBinding)
|
|
{
|
|
symbolName = BindingNameResolver.getQualifiedName((ITypeBinding) binding, m_filePath, m_compilationUnit).map(tn -> tn.toDeclName()).orElse(JavaDeclName.unsolved());
|
|
}
|
|
else if (binding instanceof IMethodBinding)
|
|
{
|
|
symbolName = BindingNameResolver.getQualifiedName((IMethodBinding) binding, m_filePath, m_compilationUnit).orElse(JavaDeclName.unsolved());
|
|
}
|
|
else if (binding instanceof IVariableBinding)
|
|
{
|
|
symbolName = BindingNameResolver.getQualifiedName((IVariableBinding) binding, m_filePath, m_compilationUnit);
|
|
}
|
|
}
|
|
|
|
for (JavaSymbolName context: m_contextStack.peek())
|
|
{
|
|
m_client.recordReference(
|
|
ReferenceKind.IMPORT,
|
|
symbolName.toNameHierarchy(), context.toNameHierarchy(),
|
|
getRange(node.getName()));
|
|
}
|
|
|
|
Optional<JavaDeclName> packageName = BindingNameResolver.getQualifiedName(getDeclaringPackage(binding), m_filePath, m_compilationUnit);
|
|
if (packageName.isPresent())
|
|
{
|
|
m_client.recordSymbol(packageName.get().toNameHierarchy(),
|
|
SymbolKind.PACKAGE, AccessKind.NONE, DefinitionKind.NONE);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(SimpleType node)
|
|
{
|
|
for (JavaSymbolName context: m_contextStack.peek())
|
|
{
|
|
ITypeBinding binding = node.resolveBinding();
|
|
if (binding != null)
|
|
{
|
|
binding = binding.getTypeDeclaration();
|
|
}
|
|
|
|
m_client.recordReference(
|
|
getTypeReferenceKind(),
|
|
BindingNameResolver.getQualifiedName(binding, m_filePath, m_compilationUnit).orElse(JavaTypeName.unsolved()).toDeclName().toNameHierarchy(),
|
|
context.toNameHierarchy(),
|
|
getRange(node));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(QualifiedType node)
|
|
{
|
|
for (JavaSymbolName context: m_contextStack.peek())
|
|
{
|
|
ITypeBinding binding = node.resolveBinding();
|
|
if (binding != null)
|
|
{
|
|
binding = binding.getTypeDeclaration();
|
|
}
|
|
|
|
m_client.recordReference(
|
|
getTypeReferenceKind(),
|
|
BindingNameResolver.getQualifiedName(binding, m_filePath, m_compilationUnit).orElse(JavaTypeName.unsolved()).toDeclName().toNameHierarchy(),
|
|
context.toNameHierarchy(),
|
|
getRange(node));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(NameQualifiedType node)
|
|
{
|
|
for (JavaSymbolName context: m_contextStack.peek())
|
|
{
|
|
ITypeBinding binding = node.resolveBinding();
|
|
if (binding != null)
|
|
{
|
|
binding = binding.getTypeDeclaration();
|
|
}
|
|
|
|
m_client.recordReference(
|
|
getTypeReferenceKind(),
|
|
BindingNameResolver.getQualifiedName(binding, m_filePath, m_compilationUnit).orElse(JavaTypeName.unsolved()).toDeclName().toNameHierarchy(),
|
|
context.toNameHierarchy(),
|
|
getRange(node));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(final PrimitiveType node)
|
|
{
|
|
NameHierarchy referencedName = JavaTypeName.fromDotSeparatedString(node.getPrimitiveTypeCode().toString()).toDeclName().toNameHierarchy();
|
|
|
|
m_client.recordSymbol(
|
|
referencedName, SymbolKind.BUILTIN_TYPE,
|
|
AccessKind.NONE,
|
|
DefinitionKind.EXPLICIT);
|
|
|
|
for (JavaSymbolName context: m_contextStack.peek())
|
|
{
|
|
m_client.recordReference(
|
|
getTypeReferenceKind(),
|
|
referencedName,
|
|
context.toNameHierarchy(),
|
|
getRange(node));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(SimpleName node)
|
|
{
|
|
IBinding binding = node.resolveBinding();
|
|
if (binding instanceof IVariableBinding)
|
|
{
|
|
IVariableBinding variableBinding = ((IVariableBinding) binding).getVariableDeclaration();
|
|
JavaDeclName declName = BindingNameResolver.getQualifiedName(
|
|
variableBinding, m_filePath, m_compilationUnit);
|
|
|
|
if (declName.getIsUnsolved() && variableBinding.getDeclaringClass() == null && variableBinding.getName().equals("length"))
|
|
{
|
|
// Do nothing. We ignore the case of unsolved symbols on array type
|
|
}
|
|
else if (declName.getIsLocal() || declName.getIsGlobal())
|
|
{
|
|
m_client.recordLocalSymbol(
|
|
declName.toNameHierarchy(), getRange(node));
|
|
}
|
|
else
|
|
{
|
|
m_client.recordSymbol(declName.toNameHierarchy(), SymbolKind.FIELD, AccessKind.NONE, DefinitionKind.NONE);
|
|
|
|
for (JavaSymbolName context: m_contextStack.peek())
|
|
{
|
|
m_client.recordReference(
|
|
ReferenceKind.USAGE,
|
|
declName.toNameHierarchy(),
|
|
context.toNameHierarchy(),
|
|
getRange(node));
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(MethodInvocation node)
|
|
{
|
|
recordReferenceToMethodDeclaration(node.resolveMethodBinding(), getRange(node.getName()), ReferenceKind.CALL, m_contextStack.peek());
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(SuperMethodInvocation node)
|
|
{
|
|
recordReferenceToMethodDeclaration(node.resolveMethodBinding(), getRange(node.getName()), ReferenceKind.CALL, m_contextStack.peek());
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(ConstructorInvocation node)
|
|
{
|
|
recordReferenceToMethodDeclaration(
|
|
node.resolveConstructorBinding(),
|
|
m_fileContent.findRange("this", getRange(node).begin),
|
|
ReferenceKind.CALL,
|
|
m_contextStack.peek());
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(SuperConstructorInvocation node)
|
|
{
|
|
recordReferenceToMethodDeclaration(
|
|
node.resolveConstructorBinding(),
|
|
m_fileContent.findRange("super", getRange(node).begin),
|
|
ReferenceKind.CALL,
|
|
m_contextStack.peek());
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(CreationReference node)
|
|
{
|
|
recordReferenceToMethodDeclaration(
|
|
node.resolveMethodBinding(),
|
|
m_fileContent.findRange("new", getRange(node).begin),
|
|
ReferenceKind.USAGE,
|
|
m_contextStack.peek());
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(ExpressionMethodReference node)
|
|
{
|
|
recordReferenceToMethodDeclaration(
|
|
node.resolveMethodBinding(),
|
|
getRange(node.getName()),
|
|
ReferenceKind.USAGE,
|
|
m_contextStack.peek());
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(SuperMethodReference node)
|
|
{
|
|
recordReferenceToMethodDeclaration(
|
|
node.resolveMethodBinding(),
|
|
getRange(node.getName()),
|
|
ReferenceKind.USAGE,
|
|
m_contextStack.peek());
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(TypeMethodReference node)
|
|
{
|
|
IMethodBinding binding = node.resolveMethodBinding();
|
|
if (binding == null && node.getType() != null && node.getType().isArrayType())
|
|
{
|
|
// Do nothing. We ignore the case of unsolved symbols on array type
|
|
}
|
|
else
|
|
{
|
|
recordReferenceToMethodDeclaration(
|
|
binding,
|
|
getRange(node.getName()),
|
|
ReferenceKind.USAGE,
|
|
m_contextStack.peek());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(ClassInstanceCreation node)
|
|
{
|
|
if (node.getAnonymousClassDeclaration() != null)
|
|
{
|
|
// record anonymous class here instead of overriding visit(AnonymousClassDeclaration node) because
|
|
// the ClassInstanceCreation still contains the Type node.
|
|
|
|
AnonymousClassDeclaration anonymousClassDeclaration = node.getAnonymousClassDeclaration();
|
|
JavaDeclName symbolName = DeclNameResolver.getQualifiedDeclName(anonymousClassDeclaration, m_filePath, m_compilationUnit);
|
|
|
|
Range anonymousClassScope = getRange(anonymousClassDeclaration);
|
|
|
|
m_client.recordSymbolWithLocationAndScope(
|
|
symbolName.toNameHierarchy(),
|
|
SymbolKind.CLASS,
|
|
new Range(anonymousClassScope.begin, anonymousClassScope.begin),
|
|
anonymousClassScope,
|
|
AccessKind.NONE,
|
|
DefinitionKind.EXPLICIT);
|
|
|
|
recordScope(anonymousClassScope);
|
|
|
|
m_contextStack.push(Arrays.asList(symbolName));
|
|
}
|
|
else
|
|
{
|
|
IMethodBinding constructorBinding = node.resolveConstructorBinding();
|
|
if (constructorBinding != null)
|
|
{
|
|
constructorBinding = constructorBinding.getMethodDeclaration();
|
|
}
|
|
|
|
JavaDeclName referencedDeclName = BindingNameResolver.getQualifiedName(constructorBinding, m_filePath, m_compilationUnit).orElse(JavaDeclName.unsolved());
|
|
if (!referencedDeclName.getIsUnsolved())
|
|
{
|
|
m_client.recordSymbol(referencedDeclName.toNameHierarchy(), SymbolKind.METHOD, AccessKind.NONE, DefinitionKind.NONE);
|
|
}
|
|
|
|
for (JavaSymbolName context: m_contextStack.peek())
|
|
{
|
|
m_client.recordReference(
|
|
ReferenceKind.CALL,
|
|
referencedDeclName.toNameHierarchy(),
|
|
context.toNameHierarchy(),
|
|
getRange(node.getType()));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void endVisit(ClassInstanceCreation node)
|
|
{
|
|
if (node.getAnonymousClassDeclaration() != null)
|
|
{
|
|
m_contextStack.pop();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(Block node)
|
|
{
|
|
recordScope(getRange(node));
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(ArrayInitializer node)
|
|
{
|
|
recordScope(getRange(node));
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(SwitchStatement node)
|
|
{
|
|
Range scopeRange = getRange(node);
|
|
scopeRange.begin = m_fileContent.findStartPosition("{", scopeRange.begin);
|
|
recordScope(scopeRange);
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(LineComment node)
|
|
{
|
|
m_client.recordComment(getRange(node));
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(BlockComment node)
|
|
{
|
|
m_client.recordComment(getRange(node));
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean visit(Javadoc node)
|
|
{
|
|
m_client.recordComment(getRange(node));
|
|
return true;
|
|
}
|
|
|
|
|
|
// --- utility methods ---
|
|
|
|
private void recordReferenceToMethodDeclaration(IMethodBinding methodBinding, Range range, ReferenceKind referenceKind, List<JavaSymbolName> contexts)
|
|
{
|
|
if (methodBinding != null)
|
|
{
|
|
// replacing type arguments of invocation with type variables of declaration
|
|
methodBinding = methodBinding.getMethodDeclaration();
|
|
}
|
|
|
|
JavaDeclName referencedDeclName = BindingNameResolver.getQualifiedName(methodBinding, m_filePath, m_compilationUnit).orElse(JavaDeclName.unsolved());
|
|
if (!referencedDeclName.getIsUnsolved())
|
|
{
|
|
m_client.recordSymbol(referencedDeclName.toNameHierarchy(), SymbolKind.METHOD, AccessKind.NONE, DefinitionKind.NONE);
|
|
}
|
|
|
|
for (JavaSymbolName context: m_contextStack.peek())
|
|
{
|
|
m_client.recordReference(
|
|
referenceKind,
|
|
referencedDeclName.toNameHierarchy(),
|
|
context.toNameHierarchy(),
|
|
range);
|
|
}
|
|
}
|
|
|
|
private void recordScope(Range range)
|
|
{
|
|
NameHierarchy nameHierarchy = JavaDeclName.scope(m_filePath, range.begin).toNameHierarchy();
|
|
m_client.recordLocalSymbol(nameHierarchy, new Range(range.begin, range.begin));
|
|
m_client.recordLocalSymbol(nameHierarchy, new Range(range.end, range.end));
|
|
}
|
|
|
|
protected Range getRange(ASTNode node)
|
|
{
|
|
return Utility.getRange(node, m_compilationUnit);
|
|
}
|
|
|
|
private IPackageBinding getDeclaringPackage(IBinding binding)
|
|
{
|
|
if (binding instanceof IPackageBinding)
|
|
{
|
|
return (IPackageBinding) binding;
|
|
}
|
|
else if (binding != null)
|
|
{
|
|
return getDeclaringPackage(BindingNameResolver.getParentBinding(binding));
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private Optional<IMethodBinding> getOverriddenMethod(IMethodBinding method)
|
|
{
|
|
if (method != null)
|
|
{
|
|
for (ITypeBinding declaringClassAncestor: getAllAncestorTypes(method.getDeclaringClass()))
|
|
{
|
|
for (IMethodBinding potentiallyOverridden: declaringClassAncestor.getDeclaredMethods())
|
|
{
|
|
if (method.overrides(potentiallyOverridden))
|
|
{
|
|
return Optional.of(potentiallyOverridden);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Optional.empty();
|
|
}
|
|
|
|
private List<ITypeBinding> getAllAncestorTypes(ITypeBinding type)
|
|
{
|
|
List<ITypeBinding> allAncestorTypes = new ArrayList<>();
|
|
|
|
List<ITypeBinding> directAncestorTypes = getDirectAncestorTypes(type);
|
|
allAncestorTypes.addAll(directAncestorTypes);
|
|
|
|
for (ITypeBinding directAncestorType: directAncestorTypes)
|
|
{
|
|
allAncestorTypes.addAll(getAllAncestorTypes(directAncestorType));
|
|
}
|
|
|
|
return allAncestorTypes;
|
|
}
|
|
|
|
private List<ITypeBinding> getDirectAncestorTypes(ITypeBinding type)
|
|
{
|
|
List<ITypeBinding> ancestorTypes = new ArrayList<>();
|
|
|
|
if (type != null)
|
|
{
|
|
ITypeBinding superclass = type.getSuperclass();
|
|
if (superclass != null)
|
|
{
|
|
ancestorTypes.add(superclass);
|
|
}
|
|
|
|
ancestorTypes.addAll(Arrays.asList(type.getInterfaces()));
|
|
}
|
|
|
|
return ancestorTypes;
|
|
}
|
|
} |