/*******************************************************************************
* Copyright (c) 2000, 2014 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
* Anton Leherbauer (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.ui.search;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.parser.Keywords;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.ui.util.Messages;
public class OccurrencesFinder implements IOccurrencesFinder {
public static final String ID= "OccurrencesFinder"; //$NON-NLS-1$
/**
* If set, don't search for implicit references.
*/
public static final int OPTION_EXCLUDE_IMPLICIT_REFERENCES = 1;
private IASTTranslationUnit fRoot;
private IASTName fSelectedNode;
private IBinding fTarget;
private List<OccurrenceLocation> fResult;
private String fReadDescription;
private String fWriteDescription;
private int fOptions;
public OccurrencesFinder() {
super();
}
@Override
public String initialize(IASTTranslationUnit root, IASTNode node) {
if (!(node instanceof IASTName))
return CSearchMessages.OccurrencesFinder_no_element;
fRoot= root;
fSelectedNode= (IASTName) node;
fTarget= fSelectedNode.resolveBinding();
if (fTarget == null)
return CSearchMessages.OccurrencesFinder_no_binding;
fReadDescription= Messages.format(CSearchMessages.OccurrencesFinder_occurrence_description, fTarget.getName());
fWriteDescription= Messages.format(CSearchMessages.OccurrencesFinder_occurrence_write_description, fTarget.getName());
return null;
}
/**
* Specify search options.
*
* @param options
*/
public void setOptions(int options) {
fOptions = options;
}
private void performSearch() {
if (fResult == null) {
fResult= new ArrayList<>();
IASTName[] names= fRoot.getDeclarationsInAST(fTarget);
for (IASTName candidate : names) {
if (candidate.isPartOfTranslationUnitFile()) {
addUsage(candidate, candidate.resolveBinding());
}
}
names= fRoot.getReferences(fTarget);
for (IASTName candidate : names) {
if (candidate.isPartOfTranslationUnitFile()) {
addUsage(candidate, candidate.resolveBinding());
}
}
if (needImplicitReferences() && canHaveImplicitReference(fTarget)) {
names= CPPVisitor.getImplicitReferences(fRoot, fTarget);
for (IASTName candidate : names) {
if (candidate.isPartOfTranslationUnitFile()) {
addUsage(candidate, candidate.resolveBinding());
}
}
}
}
}
private boolean needImplicitReferences() {
return (fOptions & OPTION_EXCLUDE_IMPLICIT_REFERENCES) == 0;
}
private boolean canHaveImplicitReference(IBinding binding) {
final char[] op = Keywords.cOPERATOR;
final char[] nameCharArray = binding.getNameCharArray();
if (nameCharArray.length > 0) {
if (nameCharArray[0] == '~') {
return true;
}
if (CharArrayUtils.equals(nameCharArray, 0, op.length, op)) {
return true;
}
}
if (binding instanceof ICPPConstructor)
return true;
return false;
}
@Override
public OccurrenceLocation[] getOccurrences() {
performSearch();
if (fResult.isEmpty())
return null;
return fResult.toArray(new OccurrenceLocation[fResult.size()]);
}
@Override
public IASTTranslationUnit getASTRoot() {
return fRoot;
}
@Override
public String getElementName() {
if (fSelectedNode != null) {
return new String(fSelectedNode.toCharArray());
}
return null;
}
@Override
public String getUnformattedPluralLabel() {
return CSearchMessages.OccurrencesFinder_label_plural;
}
@Override
public String getUnformattedSingularLabel() {
return CSearchMessages.OccurrencesFinder_label_singular;
}
private boolean addUsage(IASTName node, IBinding binding) {
if (binding != null /* && Bindings.equals(binding, fTarget) */) {
if (node instanceof ICPPASTTemplateId) {
node= ((ICPPASTTemplateId) node).getTemplateName();
}
IASTFileLocation fileLocation= node.getImageLocation();
if (fileLocation == null || !fRoot.getFilePath().equals(fileLocation.getFileName())) {
fileLocation= node.getFileLocation();
}
if (fileLocation != null) {
final int offset= fileLocation.getNodeOffset();
final int length= fileLocation.getNodeLength();
if (offset >= 0 && length > 0) {
if (binding instanceof IVariable) {
final boolean isWriteOccurrence = CSearchUtil.isWriteOccurrence(node, binding);
int flag = isWriteOccurrence ? F_WRITE_OCCURRENCE : F_READ_OCCURRENCE;
String description = isWriteOccurrence ? fWriteDescription : fReadDescription;
fResult.add(new OccurrenceLocation(offset, length, flag, description));
} else {
fResult.add(new OccurrenceLocation(offset, length, F_READ_OCCURRENCE, fWriteDescription));
}
}
}
return true;
}
return false;
}
@Override
public int getSearchKind() {
return K_OCCURRENCE;
}
@Override
public String getID() {
return ID;
}
}