| /******************************************************************************* |
| * Copyright (c) 2008, 2013 Wind River Systems, Inc. and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Markus Schorn - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.cdt.core.parser.tests.ast2; |
| |
| import java.io.IOException; |
| |
| import org.eclipse.cdt.core.dom.ast.IASTName; |
| import org.eclipse.cdt.core.dom.ast.IASTNode; |
| import org.eclipse.cdt.core.dom.ast.IASTNodeSelector; |
| import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion; |
| import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; |
| import org.eclipse.cdt.core.dom.parser.cpp.GPPParserExtensionConfiguration; |
| import org.eclipse.cdt.core.parser.FileContent; |
| import org.eclipse.cdt.core.parser.IScanner; |
| import org.eclipse.cdt.core.parser.NullLogService; |
| import org.eclipse.cdt.core.parser.ParserLanguage; |
| import org.eclipse.cdt.core.parser.ParserMode; |
| import org.eclipse.cdt.core.parser.ScannerInfo; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.GNUCPPSourceParser; |
| |
| import junit.framework.TestSuite; |
| |
| public class ASTNodeSelectorTest extends AST2TestBase { |
| |
| static public TestSuite suite() { |
| return suite(ASTNodeSelectorTest.class); |
| } |
| |
| protected String fCode; |
| protected IASTTranslationUnit fTu; |
| protected IASTNodeSelector fSelector; |
| |
| public ASTNodeSelectorTest() { |
| } |
| |
| public ASTNodeSelectorTest(String name) { |
| super(name); |
| } |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| createTranslationUnit(); |
| } |
| |
| protected void createTranslationUnit() throws IOException { |
| fCode = getContents(1)[0].toString(); |
| FileContent codeReader = FileContent.create("<test-code>", fCode.toCharArray()); |
| ScannerInfo scannerInfo = new ScannerInfo(); |
| IScanner scanner = AST2TestBase.createScanner(codeReader, ParserLanguage.CPP, ParserMode.COMPLETE_PARSE, |
| scannerInfo); |
| GNUCPPSourceParser parser = new GNUCPPSourceParser(scanner, ParserMode.COMPLETE_PARSE, new NullLogService(), |
| new GPPParserExtensionConfiguration()); |
| fTu = parser.parse(); |
| fSelector = fTu.getNodeSelector(null); |
| } |
| |
| @Override |
| protected void tearDown() throws Exception { |
| super.tearDown(); |
| } |
| |
| private void testContainedName(int from, int to, String sig) { |
| IASTName name = fSelector.findFirstContainedName(from, to - from); |
| verify(sig, name); |
| } |
| |
| private void verify(String sig, IASTNode node) { |
| if (sig == null) { |
| assertNull("unexpexted selection: " + (node == null ? "" : node.getRawSignature()), node); |
| } else { |
| assertNotNull("unable to select " + sig, node); |
| if (node instanceof IASTName) { |
| assertEquals(sig, ((IASTName) node).toString()); |
| } else { |
| assertEquals(sig, node.getRawSignature()); |
| } |
| } |
| } |
| |
| private void testContainedNode(int from, int to, String sig) { |
| IASTNode node = fSelector.findFirstContainedNode(from, to - from); |
| verify(sig, node); |
| } |
| |
| private void testName(int from, int to, String sig) { |
| IASTName name = fSelector.findName(from, to - from); |
| verify(sig, name); |
| } |
| |
| private void testNode(int from, int to, String sig) { |
| IASTNode node = fSelector.findNode(from, to - from); |
| verify(sig, node); |
| } |
| |
| private void testEnclosingName(int from, int to, String sig) { |
| IASTName name = fSelector.findEnclosingName(from, to - from); |
| verify(sig, name); |
| } |
| |
| private void testEnclosingNode(int from, int to, String sig) { |
| IASTNode node = fSelector.findEnclosingNode(from, to - from); |
| verify(sig, node); |
| } |
| |
| private void testExpansion(int from, int to, String sig) { |
| IASTPreprocessorMacroExpansion exp = fSelector.findEnclosingMacroExpansion(from, to - from); |
| verify(sig, exp); |
| } |
| |
| // #define shift_offsets |
| // int shift= shift_offsets; |
| // |
| // #include <test> |
| // int a; |
| public void testInclusion() { |
| int include_start = fCode.indexOf("#include"); |
| int name_start = fCode.indexOf("test"); |
| int include_end = fCode.indexOf(">") + 1; |
| |
| testContainedName(include_start - 1, include_end + 1, "test"); |
| testContainedName(name_start, include_end, "test"); |
| testContainedName(include_start + 1, name_start + 1, null); |
| testContainedName(name_start + 1, name_start + 7, null); |
| |
| testContainedNode(include_start - 1, include_end + 1, "#include <test>"); |
| testContainedNode(name_start, include_end, "test"); |
| testContainedNode(include_start + 1, name_start + 1, null); |
| testContainedNode(name_start + 1, name_start + 7, null); |
| |
| testEnclosingName(name_start, name_start + 4, "test"); |
| testEnclosingName(name_start, name_start, "test"); |
| testEnclosingName(name_start + 4, name_start + 4, "test"); |
| testEnclosingName(name_start - 1, name_start + 1, null); |
| testEnclosingName(name_start + 4, name_start + 5, null); |
| |
| testEnclosingNode(name_start, name_start + 4, "test"); |
| testEnclosingNode(name_start, name_start, "test"); |
| testEnclosingNode(name_start + 4, name_start + 4, "test"); |
| testEnclosingNode(name_start - 1, name_start + 1, "#include <test>"); |
| testEnclosingNode(name_start + 4 - 1, name_start + 4 + 1, "#include <test>"); |
| |
| testExpansion(name_start, name_start + 4, null); |
| } |
| |
| // #define shift_offsets |
| // int shift= shift_offsets; |
| // |
| // #define EMPTY |
| // #define TEST_H "test.h" |
| // void func() { |
| // #include EMPTY TEST_H |
| // } |
| public void testInclusionWithExpansions() { |
| int inclusion_start = fCode.indexOf("#include"); |
| int empty_start = fCode.indexOf("EMPTY", inclusion_start); |
| int testh_start = fCode.indexOf("TEST_H", empty_start); |
| int file_end = fCode.length(); |
| |
| testContainedName(inclusion_start - 1, file_end - 1, "EMPTY"); |
| testContainedName(testh_start, file_end, "TEST_H"); |
| testContainedName(testh_start + 1, file_end, null); |
| testContainedName(testh_start, testh_start + 5, null); |
| |
| testContainedNode(inclusion_start - 1, file_end + 1, "#include EMPTY TEST_H"); |
| testContainedNode(testh_start, file_end, "TEST_H"); |
| testContainedNode(testh_start + 1, file_end, null); |
| testContainedNode(testh_start, testh_start + 5, null); |
| |
| testName(empty_start, empty_start + 5, "EMPTY"); |
| testName(empty_start - 1, empty_start + 5, null); |
| testName(empty_start + 1, empty_start + 5, null); |
| testName(empty_start, empty_start + 4, null); |
| testName(empty_start, empty_start + 6, null); |
| |
| testNode(empty_start, empty_start + 5, "EMPTY"); |
| testNode(empty_start - 1, empty_start + 5, null); |
| testNode(empty_start + 1, empty_start + 5, null); |
| testNode(empty_start, empty_start + 4, null); |
| testNode(empty_start, empty_start + 6, null); |
| |
| testEnclosingName(empty_start, empty_start + 5, "EMPTY"); |
| testEnclosingName(empty_start, empty_start, "EMPTY"); |
| testEnclosingName(empty_start + 5, empty_start + 5, "EMPTY"); |
| testEnclosingName(empty_start - 1, empty_start, null); |
| testEnclosingName(empty_start + 5, empty_start + 6, "test.h"); |
| testEnclosingName(testh_start, testh_start + 6, "TEST_H"); |
| testEnclosingName(testh_start, testh_start, "TEST_H"); |
| testEnclosingName(testh_start + 6, testh_start + 6, "TEST_H"); |
| testEnclosingName(testh_start - 1, testh_start + 1, "test.h"); |
| testEnclosingName(testh_start + 5, testh_start + 7, null); |
| |
| testEnclosingNode(empty_start, empty_start + 5, "EMPTY"); |
| testEnclosingNode(empty_start, empty_start, "EMPTY"); |
| testEnclosingNode(empty_start + 5, empty_start + 5, "EMPTY"); |
| testEnclosingNode(empty_start - 1, empty_start, "#include EMPTY TEST_H"); |
| testEnclosingNode(empty_start + 5, empty_start + 6, "test.h"); |
| testEnclosingNode(testh_start, testh_start + 6, "TEST_H"); |
| testEnclosingNode(testh_start, testh_start, "TEST_H"); |
| testEnclosingNode(testh_start + 6, testh_start + 6, "TEST_H"); |
| testEnclosingNode(testh_start - 1, testh_start + 1, "test.h"); |
| testEnclosingNode(testh_start + 6 - 1, testh_start + 6 + 1, "{\n #include EMPTY TEST_H\n }"); |
| |
| testExpansion(empty_start, empty_start + 5, "EMPTY"); |
| testExpansion(empty_start, empty_start, "EMPTY"); |
| testExpansion(empty_start + 5, empty_start + 5, "EMPTY"); |
| testExpansion(empty_start - 1, empty_start, null); |
| testExpansion(empty_start + 5, empty_start + 6, null); |
| testExpansion(testh_start, testh_start + 6, "TEST_H"); |
| } |
| |
| // #define shift_offsets |
| // int shift= shift_offsets; |
| // |
| // #define xx 1 |
| // #if xx == 2 |
| // #elif xx == 1 |
| // #endif |
| public void testMacroInConditionalExpression() { |
| int x1 = fCode.indexOf("xx"); |
| int x2 = fCode.indexOf("xx", x1 + 1); |
| int x3 = fCode.indexOf("xx", x2 + 1); |
| |
| testContainedName(x1, x1 + 2, "xx"); |
| testContainedName(x2 - 1, x2 + 2, "xx"); |
| testContainedName(x3, x3 + 3, "xx"); |
| testContainedName(x1, x1 + 1, null); |
| testContainedName(x2 + 1, x2 + 2, null); |
| testContainedName(x3 + 1, x3 + 1, null); |
| |
| testName(x1, x1 + 2, "xx"); |
| testName(x2, x2 + 2, "xx"); |
| testName(x3, x3 + 2, "xx"); |
| testName(x1 + 1, x1 + 2, null); |
| testName(x2 - 1, x2 + 2, null); |
| testName(x3, x3 + 3, null); |
| testName(x3, x3 + 1, null); |
| |
| testEnclosingName(x1, x1 + 2, "xx"); |
| testEnclosingName(x2 + 2, x2 + 2, "xx"); |
| testEnclosingName(x3, x3, "xx"); |
| testEnclosingName(x1 - 1, x1 + 2, null); |
| testEnclosingName(x2 + 2, x2 + 3, null); |
| testEnclosingName(x3 - 1, x3 - 1, null); |
| |
| testExpansion(x1, x1 + 2, null); |
| testExpansion(x2 + 2, x2 + 2, "xx"); |
| testExpansion(x3, x3, "xx"); |
| testExpansion(x2 + 2, x2 + 3, null); |
| testExpansion(x3 - 1, x3 - 1, null); |
| } |
| |
| // #define shift_offsets |
| // int shift= shift_offsets; |
| // |
| // #define xx 1 |
| // #if !defined(xx) |
| // #elif defined(xx) == 1 |
| // #endif |
| public void testMacroInDefinedExpression() { |
| int x1 = fCode.indexOf("xx"); |
| int x2 = fCode.indexOf("xx", x1 + 1); |
| int x3 = fCode.indexOf("xx", x2 + 1); |
| |
| testContainedName(x1, x1 + 2, "xx"); |
| testContainedName(x2 - 1, x2 + 2, "xx"); |
| testContainedName(x3, x3 + 3, "xx"); |
| testContainedName(x1, x1 + 1, null); |
| testContainedName(x2 + 1, x2 + 2, null); |
| testContainedName(x3 + 1, x3 + 1, null); |
| |
| testName(x1, x1 + 2, "xx"); |
| testName(x2, x2 + 2, "xx"); |
| testName(x3, x3 + 2, "xx"); |
| testName(x1 + 1, x1 + 2, null); |
| testName(x2 - 1, x2 + 2, null); |
| testName(x3, x3 + 3, null); |
| testName(x3, x3 + 1, null); |
| |
| testEnclosingName(x1, x1 + 2, "xx"); |
| testEnclosingName(x2 + 2, x2 + 2, "xx"); |
| testEnclosingName(x3, x3, "xx"); |
| testEnclosingName(x1 - 1, x1 + 2, null); |
| testEnclosingName(x2 + 2, x2 + 3, null); |
| testEnclosingName(x3 - 1, x3 - 1, null); |
| |
| testExpansion(x1, x1 + 2, null); |
| testExpansion(x2 + 2, x2 + 2, null); |
| testExpansion(x3, x3, null); |
| testExpansion(x2 + 2, x2 + 3, null); |
| testExpansion(x3 - 1, x3 - 1, null); |
| } |
| |
| // #define shift_offsets |
| // int shift= shift_offsets; |
| // |
| // #define xx 1 |
| // #ifndef xx |
| // #endif |
| // #ifdef xx |
| // #endif |
| // #undef xx |
| public void testMacroInConditional() { |
| int x1 = fCode.indexOf("xx"); |
| x1 = fCode.indexOf("xx", x1 + 1); |
| int x2 = fCode.indexOf("xx", x1 + 1); |
| int x3 = fCode.indexOf("xx", x2 + 1); |
| |
| testContainedName(x1, x1 + 2, "xx"); |
| testContainedName(x2 - 1, x2 + 2, "xx"); |
| testContainedName(x3, x3 + 3, "xx"); |
| testContainedName(x1, x1 + 1, null); |
| testContainedName(x2 + 1, x2 + 2, null); |
| testContainedName(x3 + 1, x3 + 1, null); |
| |
| testName(x1, x1 + 2, "xx"); |
| testName(x2, x2 + 2, "xx"); |
| testName(x3, x3 + 2, "xx"); |
| testName(x1 + 1, x1 + 2, null); |
| testName(x2 - 1, x2 + 2, null); |
| testName(x3, x3 + 3, null); |
| testName(x3, x3 + 1, null); |
| |
| testEnclosingName(x1, x1 + 2, "xx"); |
| testEnclosingName(x2 + 2, x2 + 2, "xx"); |
| testEnclosingName(x3, x3, "xx"); |
| testEnclosingName(x1 - 1, x1 + 2, null); |
| testEnclosingName(x2 + 2, x2 + 3, null); |
| testEnclosingName(x3 - 1, x3 - 1, null); |
| |
| testExpansion(x1, x1 + 2, null); |
| testExpansion(x2 + 2, x2 + 2, null); |
| testExpansion(x3, x3, null); |
| testExpansion(x2 + 2, x2 + 3, null); |
| testExpansion(x3 - 1, x3 - 1, null); |
| } |
| |
| // #define shift_offsets |
| // int shift= shift_offsets; |
| // |
| // #define IMPLICIT 1 |
| // #define EXPLICIT IMPLICIT |
| // int a= EXPLICIT; |
| public void testUnreachableImplicitMacro() { |
| int x1 = fCode.indexOf("EXPLICIT;"); |
| testContainedName(x1, fCode.length(), "EXPLICIT"); |
| testName(x1, x1 + 8, "EXPLICIT"); |
| testEnclosingName(x1, x1, "EXPLICIT"); |
| } |
| |
| // #define shift_offsets |
| // int shift= shift_offsets; |
| // |
| // #define NESTED 1 |
| // #define EXPLICIT(x) x |
| // int a= EXPLICIT(NESTED); |
| public void testReachableNestedMacro() { |
| int x1 = fCode.indexOf("NESTED)"); |
| testContainedName(x1, fCode.length(), "NESTED"); |
| testName(x1, x1 + 6, "NESTED"); |
| testEnclosingName(x1, x1, "NESTED"); |
| } |
| |
| // #define id(x,y) x y |
| // id(int a, =1); |
| // id(int b=, a); |
| public void testImageLocations() { |
| int a1 = fCode.indexOf("a"); |
| int a2 = fCode.indexOf("a", a1 + 1); |
| int b1 = fCode.indexOf("b"); |
| |
| testName(a1, a1 + 1, "a"); |
| testContainedName(a1 - 1, a2 + 2, "a"); |
| testEnclosingName(a1, a1, "a"); |
| testEnclosingName(a1 + 1, a1 + 1, "a"); |
| |
| testName(a2, a2 + 1, "a"); |
| testContainedName(a2 - 1, a2 + 2, "a"); |
| testEnclosingName(a2, a2, "a"); |
| testEnclosingName(a2 + 1, a2 + 1, "a"); |
| |
| testEnclosingNode(a1 - 1, a1 + 1, "id(int a, =1)"); |
| testContainedNode(a1 - 8, a1 + 1, "id"); |
| } |
| |
| // namespace ns {int a;} |
| // int x= ns::a; |
| // #define M int b; |
| // M |
| // #define N() int c; |
| // N() |
| // #define O |
| // #define P() |
| // P()O |
| public void testOrdering() { |
| int x1 = fCode.indexOf("ns::a"); |
| int x2 = x1 + "ns::a".length(); |
| testContainedName(x1, x2, "ns"); |
| testEnclosingName(x2 - 1, x2 - 1, "a"); |
| testEnclosingName(x2, x2, "a"); |
| |
| x1 = fCode.indexOf("M"); |
| x1 = fCode.indexOf("M", x1 + 1); |
| testNode(x1, x1 + 1, "M"); |
| testEnclosingNode(x1, x1, "M"); |
| testEnclosingNode(x1 + 1, x1 + 1, "M"); |
| testContainedNode(x1 - 1, x1 + 2, "M"); |
| |
| x1 = fCode.indexOf("N"); |
| x1 = fCode.indexOf("N", x1 + 1); |
| testNode(x1, x1 + 1, "N"); |
| testEnclosingNode(x1, x1, "N"); |
| testEnclosingNode(x1 + 1, x1 + 1, "N"); |
| testContainedNode(x1 - 1, x1 + 2, "N"); |
| |
| x1 = fCode.indexOf("O"); |
| x1 = fCode.indexOf("O", x1 + 1); |
| testNode(x1, x1 + 1, "O"); |
| testEnclosingNode(x1, x1, "O"); |
| testEnclosingNode(x1 + 1, x1 + 1, "O"); |
| testContainedNode(x1 - 1, x1 + 2, "O"); |
| } |
| |
| // #define MACRO void m |
| // MACRO(); |
| public void testEnclosingAMacro() { |
| int x1 = fCode.indexOf("MACRO("); |
| int x2 = x1 + "MACRO(".length(); |
| testContainedName(x1, x2, "MACRO"); |
| testEnclosingNode(x1, x2, "MACRO();"); |
| } |
| } |