Skip to content

Commit 636de3b

Browse files
committed
Accommodate pre-processor lines in sticky lines provider
1 parent 48820de commit 636de3b

1 file changed

Lines changed: 65 additions & 2 deletions

File tree

core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/CSourceStickyLinesProvider.java

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
*******************************************************************************/
1515
package org.eclipse.cdt.internal.ui.editor;
1616

17+
import java.util.ArrayDeque;
18+
import java.util.Deque;
1719
import java.util.LinkedList;
1820
import java.util.List;
1921

@@ -29,6 +31,13 @@
2931
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
3032
import org.eclipse.cdt.core.dom.ast.IASTNode;
3133
import org.eclipse.cdt.core.dom.ast.IASTNodeSelector;
34+
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorElifStatement;
35+
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorElseStatement;
36+
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorEndifStatement;
37+
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfStatement;
38+
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfdefStatement;
39+
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfndefStatement;
40+
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
3241
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
3342
import org.eclipse.cdt.core.dom.ast.IASTStatement;
3443
import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement;
@@ -68,7 +77,7 @@ public class CSourceStickyLinesProvider implements IStickyLinesProvider {
6877
public List<IStickyLine> getStickyLines(ISourceViewer sourceViewer, int lineNumber,
6978
StickyLinesProperties properties) {
7079
final long startTime = System.currentTimeMillis();
71-
final LinkedList<IStickyLine> stickyLines = new LinkedList<>();
80+
List<IStickyLine> stickyLines = new LinkedList<>();
7281
// lineNumber in the zero-based line number as known to the IDocument
7382
// textWidgetLineNumber is the the line number as known to the ISourceViewer
7483
final int textWidgetLineNumber = mapLineNumberToWidget(sourceViewer, lineNumber);
@@ -119,23 +128,33 @@ public List<IStickyLine> getStickyLines(ISourceViewer sourceViewer, int lineNumb
119128
try {
120129
final int offset = sourceViewer.getDocument().getLineOffset(lineNumber);
121130
node = nodeSelector.findEnclosingNode(offset, line.length());
131+
if (node instanceof IASTPreprocessorStatement) {
132+
// find enclosing non-preprocessor node using adjusted offset
133+
final int nodeOffset = node.getFileLocation().getNodeOffset();
134+
node = nodeSelector.findEnclosingNode(nodeOffset - 1, 2);
135+
}
122136
} catch (BadLocationException e) {
123137
ILog.get().error("Error getting line offset for sticky lines", e); //$NON-NLS-1$
124138
return stickyLines;
125139
}
126140

127141
// process sticky ancestor nodes
142+
final LinkedList<IStickyLine> ancestorLines = new LinkedList<>();
128143
while (null != node) {
129144
if (DEBUG) {
130145
System.out.printf("> Examining AST node: %s (lines %d-%d)\n", node.getClass().getSimpleName(), //$NON-NLS-1$
131146
node.getFileLocation().getStartingLineNumber(),
132147
node.getFileLocation().getEndingLineNumber());
133148
}
134149
if (nodeInstanceOfStickyClass(node)) {
135-
processStickyNode(node, fileLineNumber, sourceViewer, stickyLines);
150+
processStickyNode(node, fileLineNumber, sourceViewer, ancestorLines);
136151
}
137152
node = node.getParent();
138153
}
154+
155+
// process sticky pre-processor nodes and merge with ancestor nodes
156+
final List<IStickyLine> preprocessorLines = findPreprocessorStickyLines(fileLineNumber, sourceViewer);
157+
stickyLines = mergeStickyLines(ancestorLines, preprocessorLines);
139158
}
140159
if (DEBUG) {
141160
System.out.println("> Sticky line count: " + stickyLines.size()); //$NON-NLS-1$
@@ -144,6 +163,45 @@ public List<IStickyLine> getStickyLines(ISourceViewer sourceViewer, int lineNumb
144163
return stickyLines;
145164
}
146165

166+
private List<IStickyLine> findPreprocessorStickyLines(int fileLineNumber, ISourceViewer sourceViewer) {
167+
final Deque<IASTPreprocessorStatement> stack = new ArrayDeque<>();
168+
for (IASTPreprocessorStatement statement : fAst.getAllPreprocessorStatements()) {
169+
if (statement.getFileLocation().getStartingLineNumber() >= fileLineNumber) {
170+
break;
171+
}
172+
if (nodeInstanceOfPreprocessorIfClass(statement) || statement instanceof IASTPreprocessorElifStatement
173+
|| statement instanceof IASTPreprocessorElseStatement) {
174+
stack.push(statement);
175+
} else if (statement instanceof IASTPreprocessorEndifStatement) {
176+
IASTPreprocessorStatement previous = statement;
177+
while (!stack.isEmpty() && !nodeInstanceOfPreprocessorIfClass(previous)) {
178+
previous = stack.pop();
179+
}
180+
}
181+
}
182+
final LinkedList<IStickyLine> stickyLines = new LinkedList<>();
183+
stack.forEach(statement -> addStickyLine(statement.getFileLocation().getStartingLineNumber(), sourceViewer,
184+
stickyLines));
185+
return stickyLines;
186+
}
187+
188+
private List<IStickyLine> mergeStickyLines(List<IStickyLine> lines1, List<IStickyLine> lines2) {
189+
final Deque<IStickyLine> deque1 = new ArrayDeque<>(lines1);
190+
final Deque<IStickyLine> deque2 = new ArrayDeque<>(lines2);
191+
final List<IStickyLine> mergedLines = new LinkedList<>();
192+
while (null != deque1.peek() && null != deque2.peek()) {
193+
// assume both lists are sorted in ascending line number order
194+
if (deque1.peek().getLineNumber() < deque2.peek().getLineNumber()) {
195+
mergedLines.add(deque1.pop());
196+
} else {
197+
mergedLines.add(deque2.pop());
198+
}
199+
}
200+
mergedLines.addAll(deque1);
201+
mergedLines.addAll(deque2);
202+
return mergedLines;
203+
}
204+
147205
private void processStickyNode(IASTNode node, int fileLineNumber, ISourceViewer sourceViewer,
148206
LinkedList<IStickyLine> stickyLines) {
149207
final int startingLineNumber = node.getFileLocation().getStartingLineNumber();
@@ -224,6 +282,11 @@ private boolean nodeInstanceOfStickyClass(IASTNode node) {
224282
return STICKY_NODE_CLASSES.stream().anyMatch(nodeClass -> nodeClass.isInstance(node));
225283
}
226284

285+
private boolean nodeInstanceOfPreprocessorIfClass(IASTNode node) {
286+
return node instanceof IASTPreprocessorIfStatement || node instanceof IASTPreprocessorIfdefStatement
287+
|| node instanceof IASTPreprocessorIfndefStatement;
288+
}
289+
227290
private ICElement getInputElement(IEditorPart part) {
228291
final IEditorInput editorInput = part.getEditorInput();
229292
if (null != editorInput) {

0 commit comments

Comments
 (0)