/*******************************************************************************
* Copyright (c) 2008, 2016 Institute for Software, HSR Hochschule fuer Technik
* Rapperswil, University of applied sciences 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:
* Institute for Software - initial API and implementation
* Sergey Prigogin (Google)
* Thomas Corbat (IFS)
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.utils;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.internal.ui.refactoring.Container;
/**
* Helper class to support operations concerning a selection.
*
* @author Mirko Stocker, Lukas Felber
*/
public class SelectionHelper {
public static Region getRegion(ISelection selection) {
if (selection instanceof ITextSelection) {
final ITextSelection txtSelection= (ITextSelection) selection;
return new Region(txtSelection.getOffset(), txtSelection.getLength());
}
return null;
}
public static IASTSimpleDeclaration findFirstSelectedDeclaration(final IRegion textSelection,
IASTTranslationUnit translationUnit) {
final Container<IASTSimpleDeclaration> container = new Container<>();
translationUnit.accept(new ASTVisitor() {
{
shouldVisitDeclarations = true;
}
@Override
public int visit(IASTDeclaration declaration) {
if (declaration instanceof IASTSimpleDeclaration &&
doesNodeOverlapWithRegion(declaration, textSelection)) {
container.setObject((IASTSimpleDeclaration) declaration);
}
return super.visit(declaration);
}
});
return container.getObject();
}
public static boolean doesNodeOverlapWithRegion(IASTNode node, IRegion region) {
return doRegionsOverlap(getNodeSpan(node), region);
}
public static boolean isNodeInsideRegion(IASTNode node, IRegion region) {
return isRegionInside(getNodeSpan(node), region);
}
/**
* Returns true if the first region is inside the second.
*/
private static boolean isRegionInside(IRegion region1, IRegion region2) {
int offset1 = region1.getOffset();
int offset2 = region2.getOffset();
return offset1 >= offset2 &&
offset1 + region1.getLength() <= offset2 + region2.getLength();
}
/**
* Returns true if the two regions have at least one common point.
*/
private static boolean doRegionsOverlap(IRegion region1, IRegion region2) {
int offset1 = region1.getOffset();
int offset2 = region2.getOffset();
return offset1 + region1.getLength() >= offset2 &&
offset1 <= offset2 + region2.getLength();
}
public static boolean isNodeInsideSelection(IASTNode node, IRegion selection) {
return node.isPartOfTranslationUnitFile() && isNodeInsideRegion(node, selection);
}
public static boolean isSelectionInsideNode(IASTNode node, IRegion selection) {
return node.isPartOfTranslationUnitFile() && isRegionInside(selection, getNodeSpan(node));
}
public static boolean nodeMatchesSelection(IASTNode node, IRegion region) {
return getNodeSpan(node).equals(region);
}
protected static IRegion getNodeSpan(IASTNode region) {
int start = Integer.MAX_VALUE;
int nodeLength = 0;
IASTNodeLocation[] nodeLocations = region.getNodeLocations();
if (nodeLocations.length != 1) {
for (IASTNodeLocation location : nodeLocations) {
if (location instanceof IASTMacroExpansionLocation) {
IASTMacroExpansionLocation macroLoc = (IASTMacroExpansionLocation) location;
int nodeOffset = macroLoc.asFileLocation().getNodeOffset();
if (nodeOffset < start) {
start = nodeOffset;
}
nodeLength += macroLoc.asFileLocation().getNodeLength();
} else {
IASTFileLocation loc = region.getFileLocation();
int nodeOffset = loc.getNodeOffset();
if (nodeOffset < start) {
start = nodeOffset;
}
nodeLength = loc.getNodeLength();
}
}
} else {
if (nodeLocations[0] instanceof IASTMacroExpansionLocation) {
IASTMacroExpansionLocation macroLoc = (IASTMacroExpansionLocation) nodeLocations[0];
start = macroLoc.asFileLocation().getNodeOffset();
nodeLength = macroLoc.asFileLocation().getNodeLength();
} else {
IASTFileLocation loc = region.getFileLocation();
start = loc.getNodeOffset();
nodeLength = loc.getNodeLength();
}
}
return new Region(start, nodeLength);
}
}