1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-09 18:56:02 +02:00

Bug 332191 - Expression text hover should use fallback if no parsing information is available

This commit is contained in:
Anton Leherbauer 2010-12-13 14:27:09 +00:00
parent 8e592f9a89
commit acb651e6d6

View file

@ -12,9 +12,13 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.debug.ui.editors; package org.eclipse.cdt.debug.ui.editors;
import java.util.EmptyStackException;
import java.util.Stack;
import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression; import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTFieldReference; import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
@ -26,7 +30,14 @@ import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation;
import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorElifStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorElseStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorEndifStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfdefStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfndefStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression; import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression;
@ -79,7 +90,7 @@ public abstract class AbstractDebugTextHover implements ICEditorTextHover, IText
fValid = true; fValid = true;
node.accept(this); node.accept(this);
return fValid; return fValid;
}; }
@Override @Override
public int visit(IASTExpression expression) { public int visit(IASTExpression expression) {
if (expression instanceof IASTFunctionCallExpression) { if (expression instanceof IASTFunctionCallExpression) {
@ -97,6 +108,7 @@ public abstract class AbstractDebugTextHover implements ICEditorTextHover, IText
} else if (expression instanceof IASTBinaryExpression) { } else if (expression instanceof IASTBinaryExpression) {
IASTBinaryExpression binaryExpression = (IASTBinaryExpression) expression; IASTBinaryExpression binaryExpression = (IASTBinaryExpression) expression;
switch (binaryExpression.getOperator()) { switch (binaryExpression.getOperator()) {
case IASTBinaryExpression.op_assign:
case IASTBinaryExpression.op_binaryAndAssign: case IASTBinaryExpression.op_binaryAndAssign:
case IASTBinaryExpression.op_binaryOrAssign: case IASTBinaryExpression.op_binaryOrAssign:
case IASTBinaryExpression.op_binaryXorAssign: case IASTBinaryExpression.op_binaryXorAssign:
@ -160,11 +172,8 @@ public abstract class AbstractDebugTextHover implements ICEditorTextHover, IText
} }
return null; return null;
} }
public IRegion getHoverRegion(ITextViewer viewer, int offset) { public IRegion getHoverRegion(ITextViewer viewer, int offset) {
/*
* Point selectedRange = viewer.getSelectedRange(); if ( selectedRange.x >= 0 && selectedRange.y > 0 && offset >= selectedRange.x && offset <=
* selectedRange.x + selectedRange.y ) return new Region( selectedRange.x, selectedRange.y );
*/
if (viewer != null) if (viewer != null)
return CDebugUIUtils.findWord(viewer.getDocument(), offset); return CDebugUIUtils.findWord(viewer.getDocument(), offset);
return null; return null;
@ -180,7 +189,6 @@ public abstract class AbstractDebugTextHover implements ICEditorTextHover, IText
return null; return null;
} }
/** /**
* Compute the expression text to be evaluated by the debugger. * Compute the expression text to be evaluated by the debugger.
* <p> * <p>
@ -196,13 +204,42 @@ public abstract class AbstractDebugTextHover implements ICEditorTextHover, IText
IDocument document = textViewer.getDocument(); IDocument document = textViewer.getDocument();
if (document == null) if (document == null)
return null; return null;
String expression = getExpressionTextFromAST(document, hoverRegion);
if (expression == null) {
// fallback in case no parsing information is available
try {
return document.get(hoverRegion.getOffset(), hoverRegion.getLength());
} catch (BadLocationException e) {
// ignored
}
} else if (expression.length() == 0) {
// positively invalid expression
return null;
}
return expression;
}
/**
* Compute a valid expression from AST if available.
*
* @param document
* @param hoverRegion
* @return a valid expression string, an empty string to indicate an invalid
* expression or <code>null</code> if the expression could not be
* validated
*/
private String getExpressionTextFromAST(IDocument document, final IRegion hoverRegion) {
ICElement cElement = CDTUITools.getEditorInputCElement(getEditor().getEditorInput()); ICElement cElement = CDTUITools.getEditorInputCElement(getEditor().getEditorInput());
if (cElement instanceof ITranslationUnit) { if (!(cElement instanceof ITranslationUnit)) {
return null;
}
final Position expressionPosition = new Position(0); final Position expressionPosition = new Position(0);
SharedASTJob job = new SharedASTJob(CDebugUIMessages.getString("AbstractDebugTextHover.jobName"), (ITranslationUnit) cElement) { //$NON-NLS-1$ SharedASTJob job = new SharedASTJob(CDebugUIMessages.getString("AbstractDebugTextHover.jobName"), (ITranslationUnit) cElement) { //$NON-NLS-1$
@Override @Override
public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) throws CoreException { public IStatus runOnAST(ILanguage lang, IASTTranslationUnit ast) throws CoreException {
if (ast != null) { if (ast == null) {
return Status.CANCEL_STATUS;
}
int offset = hoverRegion.getOffset(); int offset = hoverRegion.getOffset();
int length = hoverRegion.getLength(); int length = hoverRegion.getLength();
IASTName name= ast.getNodeSelector(null).findEnclosingName(offset, length); IASTName name= ast.getNodeSelector(null).findEnclosingName(offset, length);
@ -211,7 +248,7 @@ public abstract class AbstractDebugTextHover implements ICEditorTextHover, IText
int kind = imageLoc.getLocationKind(); int kind = imageLoc.getLocationKind();
switch (kind) { switch (kind) {
case IASTImageLocation.ARGUMENT_TO_MACRO_EXPANSION: case IASTImageLocation.ARGUMENT_TO_MACRO_EXPANSION:
computeMacroArgumentExtent(expressionPosition, name); computeMacroArgumentExtent(name, expressionPosition);
break; break;
default: default:
if (name.getParent() instanceof IASTPreprocessorMacroExpansion) { if (name.getParent() instanceof IASTPreprocessorMacroExpansion) {
@ -228,17 +265,21 @@ public abstract class AbstractDebugTextHover implements ICEditorTextHover, IText
} }
} }
} else { } else {
// not a name, but might still be an expression (e.g. this) // not a name, but might still be an expression (e.g. this or a selected expression)
IASTNode node = ast.getNodeSelector(null).findFirstContainedNode(offset, length); IASTNode node = ast.getNodeSelector(null).findEnclosingNode(offset, length);
if (!(node instanceof IASTExpression)) {
node = ast.getNodeSelector(null).findFirstContainedNode(offset, length);
}
if (node instanceof IASTExpression) { if (node instanceof IASTExpression) {
computeExpressionExtent(node, expressionPosition); computeExpressionExtent(node, expressionPosition);
} } else if (node == null && insideInactiveCode(ast, offset) && !insideComment(ast, offset)) {
return Status.CANCEL_STATUS;
} }
} }
return Status.OK_STATUS; return Status.OK_STATUS;
} }
private void computeMacroArgumentExtent(final Position pos, IASTName name) { private void computeMacroArgumentExtent(IASTName name, Position pos) {
IASTImageLocation imageLoc = name.getImageLocation(); IASTImageLocation imageLoc = name.getImageLocation();
int startOffset = imageLoc.getNodeOffset(); int startOffset = imageLoc.getNodeOffset();
int endOffset = startOffset + imageLoc.getNodeLength(); int endOffset = startOffset + imageLoc.getNodeLength();
@ -297,6 +338,111 @@ public abstract class AbstractDebugTextHover implements ICEditorTextHover, IText
pos.length = loc.getNodeLength(); pos.length = loc.getNodeLength();
} }
} }
private boolean insideInactiveCode(IASTTranslationUnit ast, int offset) {
int inactiveCodeStart = -1;
boolean inInactiveCode = false;
Stack<Boolean> inactiveCodeStack = new Stack<Boolean>();
IASTPreprocessorStatement[] preprocStmts = ast.getAllPreprocessorStatements();
for (IASTPreprocessorStatement preprocStmt : preprocStmts) {
IASTPreprocessorStatement statement = preprocStmt;
if (!statement.isPartOfTranslationUnitFile()) {
continue;
}
IASTNodeLocation nodeLocation = statement.getFileLocation();
if (nodeLocation == null) {
continue;
}
int nodeOffset = nodeLocation.getNodeOffset();
int nodeEnd = nodeOffset + nodeLocation.getNodeLength();
if (nodeOffset <= offset && offset < nodeEnd) {
// inside preprocessor directive
return false;
}
if (statement instanceof IASTPreprocessorIfStatement) {
IASTPreprocessorIfStatement ifStmt = (IASTPreprocessorIfStatement)statement;
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
if (!ifStmt.taken()) {
if (!inInactiveCode) {
inactiveCodeStart = nodeEnd;
inInactiveCode = true;
}
}
} else if (statement instanceof IASTPreprocessorIfdefStatement) {
IASTPreprocessorIfdefStatement ifdefStmt = (IASTPreprocessorIfdefStatement)statement;
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
if (!ifdefStmt.taken()) {
if (!inInactiveCode) {
inactiveCodeStart = nodeEnd;
inInactiveCode = true;
}
}
} else if (statement instanceof IASTPreprocessorIfndefStatement) {
IASTPreprocessorIfndefStatement ifndefStmt = (IASTPreprocessorIfndefStatement)statement;
inactiveCodeStack.push(Boolean.valueOf(inInactiveCode));
if (!ifndefStmt.taken()) {
if (!inInactiveCode) {
inactiveCodeStart = nodeEnd;
inInactiveCode = true;
}
}
} else if (statement instanceof IASTPreprocessorElseStatement) {
IASTPreprocessorElseStatement elseStmt = (IASTPreprocessorElseStatement)statement;
if (!elseStmt.taken() && !inInactiveCode) {
inactiveCodeStart = nodeEnd;
inInactiveCode = true;
} else if (elseStmt.taken() && inInactiveCode) {
int inactiveCodeEnd = nodeOffset;
if (inactiveCodeStart <= offset && offset < inactiveCodeEnd) {
return true;
}
inInactiveCode = false;
}
} else if (statement instanceof IASTPreprocessorElifStatement) {
IASTPreprocessorElifStatement elifStmt = (IASTPreprocessorElifStatement)statement;
if (!elifStmt.taken() && !inInactiveCode) {
inactiveCodeStart = nodeEnd;
inInactiveCode = true;
} else if (elifStmt.taken() && inInactiveCode) {
int inactiveCodeEnd = nodeOffset;
if (inactiveCodeStart <= offset && offset < inactiveCodeEnd) {
return true;
}
inInactiveCode = false;
}
} else if (statement instanceof IASTPreprocessorEndifStatement) {
try {
boolean wasInInactiveCode = inactiveCodeStack.pop().booleanValue();
if (inInactiveCode && !wasInInactiveCode) {
int inactiveCodeEnd = nodeOffset;
if (inactiveCodeStart <= offset && offset < inactiveCodeEnd) {
return true;
}
}
inInactiveCode = wasInInactiveCode;
}
catch (EmptyStackException e) {}
}
}
return false;
}
private boolean insideComment(IASTTranslationUnit ast, int offset) {
IASTComment[] comments = ast.getComments();
for (IASTComment comment : comments) {
if (!comment.isPartOfTranslationUnitFile()) {
continue;
}
IASTNodeLocation location = comment.getFileLocation();
if (location != null) {
if (location.getNodeOffset() <= offset && offset < location.getNodeOffset() + location.getNodeLength()) {
return true;
}
}
}
return false;
}
}; };
job.setPriority(Job.SHORT); job.setPriority(Job.SHORT);
job.setSystem(true); job.setSystem(true);
@ -307,6 +453,10 @@ public abstract class AbstractDebugTextHover implements ICEditorTextHover, IText
job.cancel(); job.cancel();
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} }
if (!job.getResult().isOK()) {
// indeterminate result
return null;
}
if (expressionPosition.getLength() > 0) { if (expressionPosition.getLength() > 0) {
try { try {
// Get expression text removing comments, obsolete whitespace, etc. // Get expression text removing comments, obsolete whitespace, etc.
@ -327,8 +477,8 @@ public abstract class AbstractDebugTextHover implements ICEditorTextHover, IText
} catch (BadLocationException exc) { } catch (BadLocationException exc) {
} }
} }
} // return empty string to indicate invalid expression
return null; return ""; //$NON-NLS-1$
} }
/** /**