org.aspectj.org.eclipse.jdt.internal.core.search.matching.FieldLocator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
Tools from the AspectJ project
/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.core.search.matching;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.aspectj.org.eclipse.jdt.core.*;
import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
import org.aspectj.org.eclipse.jdt.core.search.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.SimpleSet;
import org.aspectj.org.eclipse.jdt.internal.core.JavaElement;
public class FieldLocator extends VariableLocator {
protected boolean isDeclarationOfAccessedFieldsPattern;
public FieldLocator(FieldPattern pattern) {
super(pattern);
this.isDeclarationOfAccessedFieldsPattern = this.pattern instanceof DeclarationOfAccessedFieldsPattern;
}
protected int fineGrain() {
return this.pattern.fineGrain;
}
public int match(ASTNode node, MatchingNodeSet nodeSet) {
int declarationsLevel = IMPOSSIBLE_MATCH;
if (this.pattern.findReferences) {
if (node instanceof ImportReference) {
// With static import, we can have static field reference in import reference
ImportReference importRef = (ImportReference) node;
int length = importRef.tokens.length-1;
if (importRef.isStatic() && ((importRef.bits & ASTNode.OnDemand) == 0) && matchesName(this.pattern.name, importRef.tokens[length])) {
char[][] compoundName = new char[length][];
System.arraycopy(importRef.tokens, 0, compoundName, 0, length);
FieldPattern fieldPattern = (FieldPattern) this.pattern;
char[] declaringType = CharOperation.concat(fieldPattern.declaringQualification, fieldPattern.declaringSimpleName, '.');
if (matchesName(declaringType, CharOperation.concatWith(compoundName, '.'))) {
declarationsLevel = this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
}
}
}
}
return nodeSet.addMatch(node, declarationsLevel);
}
//public int match(ConstructorDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
public int match(FieldDeclaration node, MatchingNodeSet nodeSet) {
int referencesLevel = IMPOSSIBLE_MATCH;
if (this.pattern.findReferences)
// must be a write only access with an initializer
if (this.pattern.writeAccess && !this.pattern.readAccess && node.initialization != null)
if (matchesName(this.pattern.name, node.name))
referencesLevel = this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
int declarationsLevel = IMPOSSIBLE_MATCH;
if (this.pattern.findDeclarations) {
switch (node.getKind()) {
case AbstractVariableDeclaration.FIELD :
case AbstractVariableDeclaration.ENUM_CONSTANT :
if (matchesName(this.pattern.name, node.name))
if (matchesTypeReference(((FieldPattern)this.pattern).typeSimpleName, node.type))
declarationsLevel = this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
break;
}
}
return nodeSet.addMatch(node, referencesLevel >= declarationsLevel ? referencesLevel : declarationsLevel); // use the stronger match
}
//public int match(MethodDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
//public int match(MessageSend node, MatchingNodeSet nodeSet) - SKIP IT
//public int match(TypeDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
//public int match(TypeReference node, MatchingNodeSet nodeSet) - SKIP IT
protected int matchContainer() {
if (this.pattern.findReferences || this.pattern.fineGrain != 0) {
// need to look everywhere to find in javadocs and static import
return ALL_CONTAINER;
}
return CLASS_CONTAINER;
}
protected int matchField(FieldBinding field, boolean matchName) {
if (field == null) return INACCURATE_MATCH;
if (matchName && !matchesName(this.pattern.name, field.readableName())) return IMPOSSIBLE_MATCH;
FieldPattern fieldPattern = (FieldPattern)this.pattern;
ReferenceBinding receiverBinding = field.declaringClass;
if (receiverBinding == null) {
if (field == ArrayBinding.ArrayLength)
// optimized case for length field of an array
return fieldPattern.declaringQualification == null && fieldPattern.declaringSimpleName == null
? ACCURATE_MATCH
: IMPOSSIBLE_MATCH;
return INACCURATE_MATCH;
}
// Note there is no dynamic lookup for field access
int declaringLevel = resolveLevelForType(fieldPattern.declaringSimpleName, fieldPattern.declaringQualification, receiverBinding);
if (declaringLevel == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH;
// look at field type only if declaring type is not specified
if (fieldPattern.declaringSimpleName == null) return declaringLevel;
// get real field binding
FieldBinding fieldBinding = field;
if (field instanceof ParameterizedFieldBinding) {
fieldBinding = ((ParameterizedFieldBinding) field).originalField;
}
int typeLevel = resolveLevelForType(fieldBinding.type);
return declaringLevel > typeLevel ? typeLevel : declaringLevel; // return the weaker match
}
/* (non-Javadoc)
* @see org.aspectj.org.eclipse.jdt.internal.core.search.matching.PatternLocator#matchLevelAndReportImportRef(org.aspectj.org.eclipse.jdt.internal.compiler.ast.ImportReference, org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding, org.aspectj.org.eclipse.jdt.internal.core.search.matching.MatchLocator)
* Accept to report match of static field on static import
*/
protected void matchLevelAndReportImportRef(ImportReference importRef, Binding binding, MatchLocator locator) throws CoreException {
if (importRef.isStatic() && binding instanceof FieldBinding) {
super.matchLevelAndReportImportRef(importRef, binding, locator);
}
}
protected int matchReference(Reference node, MatchingNodeSet nodeSet, boolean writeOnlyAccess) {
if (node instanceof FieldReference) {
if (matchesName(this.pattern.name, ((FieldReference) node).token))
return nodeSet.addMatch(node, this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);
return IMPOSSIBLE_MATCH;
}
return super.matchReference(node, nodeSet, writeOnlyAccess);
}
protected void matchReportReference(ASTNode reference, IJavaElement element, Binding elementBinding, int accuracy, MatchLocator locator) throws CoreException {
matchReportReference(reference, element, null, null, elementBinding, accuracy, locator);
}
protected void matchReportReference(ASTNode reference, IJavaElement element, IJavaElement localElement, IJavaElement[] otherElements,Binding elementBinding, int accuracy, MatchLocator locator) throws CoreException {
if (this.isDeclarationOfAccessedFieldsPattern) {
// need exact match to be able to open on type ref
if (accuracy != SearchMatch.A_ACCURATE) return;
// element that references the field must be included in the enclosing element
DeclarationOfAccessedFieldsPattern declPattern = (DeclarationOfAccessedFieldsPattern) this.pattern;
while (element != null && !declPattern.enclosingElement.equals(element))
element = element.getParent();
if (element != null) {
if (reference instanceof FieldReference) {
reportDeclaration(((FieldReference) reference).binding, locator, declPattern.knownFields);
} else if (reference instanceof QualifiedNameReference) {
QualifiedNameReference qNameRef = (QualifiedNameReference) reference;
Binding nameBinding = qNameRef.binding;
if (nameBinding instanceof FieldBinding)
reportDeclaration((FieldBinding)nameBinding, locator, declPattern.knownFields);
int otherMax = qNameRef.otherBindings == null ? 0 : qNameRef.otherBindings.length;
for (int i = 0; i < otherMax; i++)
reportDeclaration(qNameRef.otherBindings[i], locator, declPattern.knownFields);
} else if (reference instanceof SingleNameReference) {
reportDeclaration((FieldBinding)((SingleNameReference) reference).binding, locator, declPattern.knownFields);
}
}
} else if (reference instanceof ImportReference) {
ImportReference importRef = (ImportReference) reference;
long[] positions = importRef.sourcePositions;
int lastIndex = importRef.tokens.length - 1;
int start = (int) ((positions[lastIndex]) >>> 32);
int end = (int) positions[lastIndex];
this.match = locator.newFieldReferenceMatch(element, localElement, elementBinding, accuracy, start, end-start+1, importRef);
locator.report(this.match);
} else if (reference instanceof FieldReference) {
FieldReference fieldReference = (FieldReference) reference;
long position = fieldReference.nameSourcePosition;
int start = (int) (position >>> 32);
int end = (int) position;
this.match = locator.newFieldReferenceMatch(element, localElement, elementBinding, accuracy, start, end-start+1, fieldReference);
locator.report(this.match);
} else if (reference instanceof SingleNameReference) {
int offset = reference.sourceStart;
this.match = locator.newFieldReferenceMatch(element, localElement, elementBinding, accuracy, offset, reference.sourceEnd-offset+1, reference);
locator.report(this.match);
} else if (reference instanceof QualifiedNameReference) {
QualifiedNameReference qNameRef = (QualifiedNameReference) reference;
int length = qNameRef.tokens.length;
SearchMatch[] matches = new SearchMatch[length];
Binding nameBinding = qNameRef.binding;
int indexOfFirstFieldBinding = qNameRef.indexOfFirstFieldBinding > 0 ? qNameRef.indexOfFirstFieldBinding-1 : 0;
// first token
if (matchesName(this.pattern.name, qNameRef.tokens[indexOfFirstFieldBinding]) && !(nameBinding instanceof LocalVariableBinding)) {
FieldBinding fieldBinding = nameBinding instanceof FieldBinding ? (FieldBinding) nameBinding : null;
if (fieldBinding == null) {
matches[indexOfFirstFieldBinding] = locator.newFieldReferenceMatch(element, localElement, elementBinding, accuracy, -1, -1, reference);
} else {
switch (matchField(fieldBinding, false)) {
case ACCURATE_MATCH:
matches[indexOfFirstFieldBinding] = locator.newFieldReferenceMatch(element, localElement, elementBinding, SearchMatch.A_ACCURATE, -1, -1, reference);
break;
case INACCURATE_MATCH:
this.match = locator.newFieldReferenceMatch(element, localElement, elementBinding, SearchMatch.A_INACCURATE, -1, -1, reference);
if (fieldBinding.type != null && fieldBinding.type.isParameterizedType() && this.pattern.hasTypeArguments()) {
updateMatch((ParameterizedTypeBinding) fieldBinding.type, this.pattern.getTypeArguments(), locator);
}
matches[indexOfFirstFieldBinding] = this.match;
break;
}
}
}
// other tokens
for (int i = indexOfFirstFieldBinding+1; i < length; i++) {
char[] token = qNameRef.tokens[i];
if (matchesName(this.pattern.name, token)) {
FieldBinding otherBinding = qNameRef.otherBindings == null ? null : qNameRef.otherBindings[i-(indexOfFirstFieldBinding+1)];
if (otherBinding == null) {
matches[i] = locator.newFieldReferenceMatch(element, localElement, elementBinding, accuracy, -1, -1, reference);
} else {
switch (matchField(otherBinding, false)) {
case ACCURATE_MATCH:
matches[i] = locator.newFieldReferenceMatch(element, localElement, elementBinding, SearchMatch.A_ACCURATE, -1, -1, reference);
break;
case INACCURATE_MATCH:
this.match = locator.newFieldReferenceMatch(element, localElement, elementBinding, SearchMatch.A_INACCURATE, -1, -1, reference);
if (otherBinding.type != null && otherBinding.type.isParameterizedType() && this.pattern.hasTypeArguments()) {
updateMatch((ParameterizedTypeBinding) otherBinding.type, this.pattern.getTypeArguments(), locator);
}
matches[i] = this.match;
break;
}
}
}
}
locator.reportAccurateFieldReference(matches, qNameRef);
}
}
/* (non-Javadoc)
* Overridden to reject unexact matches.
* @see org.aspectj.org.eclipse.jdt.internal.core.search.matching.PatternLocator#updateMatch(org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding, char[][][], org.aspectj.org.eclipse.jdt.internal.core.search.matching.MatchLocator)
*
*/
protected void updateMatch(ParameterizedTypeBinding parameterizedBinding, char[][][] patternTypeArguments, MatchLocator locator) {
// We can only refine if locator has an unit scope.
if (locator.unitScope == null) return;
updateMatch(parameterizedBinding, patternTypeArguments, false, 0, locator);
if (!this.match.isExact()) {
// cannot accept neither erasure nor compatible match
this.match.setRule(0);
}
}
protected void reportDeclaration(FieldBinding fieldBinding, MatchLocator locator, SimpleSet knownFields) throws CoreException {
// ignore length field
if (fieldBinding == ArrayBinding.ArrayLength) return;
ReferenceBinding declaringClass = fieldBinding.declaringClass;
IType type = locator.lookupType(declaringClass);
if (type == null) return; // case of a secondary type
char[] bindingName = fieldBinding.name;
IField field = type.getField(new String(bindingName));
if (knownFields.addIfNotIncluded(field) == null) return;
IResource resource = type.getResource();
boolean isBinary = type.isBinary();
IBinaryType info = null;
if (isBinary) {
if (resource == null)
resource = type.getJavaProject().getProject();
info = locator.getBinaryInfo((org.aspectj.org.eclipse.jdt.internal.core.ClassFile) type.getClassFile(), resource);
locator.reportBinaryMemberDeclaration(resource, field, fieldBinding, info, SearchMatch.A_ACCURATE);
} else {
if (declaringClass instanceof ParameterizedTypeBinding)
declaringClass = ((ParameterizedTypeBinding) declaringClass).genericType();
ClassScope scope = ((SourceTypeBinding) declaringClass).scope;
if (scope != null) {
TypeDeclaration typeDecl = scope.referenceContext;
FieldDeclaration fieldDecl = null;
FieldDeclaration[] fieldDecls = typeDecl.fields;
int length = fieldDecls == null ? 0 : fieldDecls.length;
for (int i = 0; i < length; i++) {
if (CharOperation.equals(bindingName, fieldDecls[i].name)) {
fieldDecl = fieldDecls[i];
break;
}
}
if (fieldDecl != null) {
int offset = fieldDecl.sourceStart;
this.match = new FieldDeclarationMatch(((JavaElement) field).resolved(fieldBinding), SearchMatch.A_ACCURATE, offset, fieldDecl.sourceEnd-offset+1, locator.getParticipant(), resource);
locator.report(this.match);
}
}
}
}
protected int referenceType() {
return IJavaElement.FIELD;
}
public int resolveLevel(ASTNode possiblelMatchingNode) {
if (this.pattern.findReferences || this.pattern.fineGrain != 0) {
if (possiblelMatchingNode instanceof FieldReference)
return matchField(((FieldReference) possiblelMatchingNode).binding, true);
else if (possiblelMatchingNode instanceof NameReference)
return resolveLevel((NameReference) possiblelMatchingNode);
}
if (possiblelMatchingNode instanceof FieldDeclaration)
return matchField(((FieldDeclaration) possiblelMatchingNode).binding, true);
return IMPOSSIBLE_MATCH;
}
public int resolveLevel(Binding binding) {
if (binding == null) return INACCURATE_MATCH;
if (!(binding instanceof FieldBinding)) return IMPOSSIBLE_MATCH;
return matchField((FieldBinding) binding, true);
}
protected int resolveLevel(NameReference nameRef) {
if (nameRef instanceof SingleNameReference)
return resolveLevel(nameRef.binding);
Binding binding = nameRef.binding;
QualifiedNameReference qNameRef = (QualifiedNameReference) nameRef;
FieldBinding fieldBinding = null;
if (binding instanceof FieldBinding) {
fieldBinding = (FieldBinding) binding;
char[] bindingName = fieldBinding.name;
int lastDot = CharOperation.lastIndexOf('.', bindingName);
if (lastDot > -1)
bindingName = CharOperation.subarray(bindingName, lastDot+1, bindingName.length);
if (matchesName(this.pattern.name, bindingName)) {
int level = matchField(fieldBinding, false);
if (level != IMPOSSIBLE_MATCH) return level;
}
}
int otherMax = qNameRef.otherBindings == null ? 0 : qNameRef.otherBindings.length;
for (int i = 0; i < otherMax; i++) {
char[] token = qNameRef.tokens[i + qNameRef.indexOfFirstFieldBinding];
if (matchesName(this.pattern.name, token)) {
FieldBinding otherBinding = qNameRef.otherBindings[i];
int level = matchField(otherBinding, false);
if (level != IMPOSSIBLE_MATCH) return level;
}
}
return IMPOSSIBLE_MATCH;
}
/* (non-Javadoc)
* Resolve level for type with a given binding.
*/
protected int resolveLevelForType(TypeBinding typeBinding) {
FieldPattern fieldPattern = (FieldPattern) this.pattern;
TypeBinding fieldTypeBinding = typeBinding;
if (fieldTypeBinding != null && fieldTypeBinding.isParameterizedType()) {
fieldTypeBinding = typeBinding.erasure();
}
return resolveLevelForType(
fieldPattern.typeSimpleName,
fieldPattern.typeQualification,
fieldPattern.getTypeArguments(),
0,
fieldTypeBinding);
}
}