| /******************************************************************************* |
| * Copyright (c) 2006, 2013 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.cdt.core.lrparser.tests; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.cdt.core.dom.ICodeReaderFactory; |
| import org.eclipse.cdt.core.dom.ast.ASTVisitor; |
| import org.eclipse.cdt.core.dom.ast.IASTCompletionNode; |
| import org.eclipse.cdt.core.dom.ast.IASTName; |
| import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; |
| import org.eclipse.cdt.core.dom.ast.IBinding; |
| import org.eclipse.cdt.core.dom.ast.IProblemBinding; |
| import org.eclipse.cdt.core.model.ILanguage; |
| import org.eclipse.cdt.core.parser.CodeReader; |
| import org.eclipse.cdt.core.parser.FileContent; |
| import org.eclipse.cdt.core.parser.IScannerInfo; |
| import org.eclipse.cdt.core.parser.IncludeFileContentProvider; |
| import org.eclipse.cdt.core.parser.ParserUtil; |
| import org.eclipse.cdt.core.parser.ScannerInfo; |
| import org.eclipse.cdt.core.parser.tests.ast2.AST2TestBase; |
| import org.eclipse.cdt.internal.core.dom.parser.c.CVisitor; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase; |
| import org.eclipse.core.runtime.CoreException; |
| |
| import junit.framework.AssertionFailedError; |
| |
| /** |
| * Utility methods for parsing test code using the C99 LPG parser. |
| * |
| * @author Mike Kucera |
| */ |
| @SuppressWarnings({ "restriction", "nls" }) |
| public class ParseHelper { |
| |
| static int testsRun = 0; |
| |
| static protected class NameResolver extends ASTVisitor { |
| { |
| shouldVisitNames = true; |
| } |
| |
| public List<IASTName> nameList = new ArrayList<>(); |
| public List<String> problemBindings = new ArrayList<>(); |
| public int numNullBindings = 0; |
| |
| @Override |
| public int visit(IASTName name) { |
| nameList.add(name); |
| IBinding binding = name.resolveBinding(); |
| if (binding instanceof IProblemBinding) { |
| // Suppress assertion that would be thrown for computing string representation |
| // of template-ids. The flag will be reset by BaseTestCase.setUp(). |
| CPPASTNameBase.sAllowNameComputation = true; |
| problemBindings.add(name.toString()); |
| } |
| if (binding == null) |
| numNullBindings++; |
| return PROCESS_CONTINUE; |
| } |
| |
| public IASTName getName(int idx) { |
| if (idx < 0 || idx >= nameList.size()) |
| return null; |
| return nameList.get(idx); |
| } |
| |
| public int size() { |
| return nameList.size(); |
| } |
| } |
| |
| public static class Options { |
| |
| boolean checkSyntaxProblems = true; |
| boolean checkPreprocessorProblems = true; |
| boolean checkBindings = false; |
| |
| int expectedProblemBindings; |
| String[] problems; |
| int limitTrivialInitializers = -1; |
| |
| public Options setCheckSyntaxProblems(boolean checkSyntaxProblems) { |
| this.checkSyntaxProblems = checkSyntaxProblems; |
| return this; |
| } |
| |
| public Options setCheckBindings(boolean checkBindings) { |
| this.checkBindings = checkBindings; |
| return this; |
| } |
| |
| public Options setCheckPreprocessorProblems(boolean checkPreprocessorProblems) { |
| this.checkPreprocessorProblems = checkPreprocessorProblems; |
| return this; |
| } |
| |
| public Options setExpectedProblemBindings(int expectedProblemBindings) { |
| this.expectedProblemBindings = expectedProblemBindings; |
| return this; |
| } |
| |
| public Options setProblems(String[] problems) { |
| this.problems = problems; |
| setExpectedProblemBindings(problems.length); |
| setCheckBindings(true); |
| return this; |
| } |
| |
| public Options setLimitTrivialInitializers(int limitTrivialInitializers) { |
| this.limitTrivialInitializers = limitTrivialInitializers; |
| return this; |
| } |
| |
| } |
| |
| public static IASTTranslationUnit parse(String code, ILanguage lang, boolean expectNoProblems) { |
| Options options = new Options().setCheckSyntaxProblems(expectNoProblems) |
| .setCheckPreprocessorProblems(expectNoProblems); |
| return parse(code.toCharArray(), lang, options); |
| } |
| |
| public static IASTTranslationUnit parse(String code, ILanguage lang, Options options) { |
| return parse(code.toCharArray(), lang, options); |
| } |
| |
| public static IASTTranslationUnit parse(char[] code, ILanguage lang, Options options) { |
| |
| return parse(FileContent.create(AST2TestBase.TEST_CODE, code), lang, new ScannerInfo(), null, options); |
| } |
| |
| /** |
| * TODO thats WAY too many parameters, need to use a parameter object, need to refactor the |
| * DOM parser test suite so that its a lot cleaner. |
| * @Deprecated |
| */ |
| public static IASTTranslationUnit parse(CodeReader codeReader, ILanguage language, IScannerInfo scanInfo, |
| ICodeReaderFactory fileCreator, Options options) { |
| testsRun++; |
| |
| IASTTranslationUnit tu; |
| try { |
| int languageOptions = 0; |
| if (options.limitTrivialInitializers >= 0 && options.limitTrivialInitializers != Integer.MAX_VALUE) |
| languageOptions |= ILanguage.OPTION_SKIP_TRIVIAL_EXPRESSIONS_IN_AGGREGATE_INITIALIZERS; |
| |
| tu = language.getASTTranslationUnit(codeReader, scanInfo, fileCreator, null, languageOptions, |
| ParserUtil.getParserLogService()); |
| } catch (CoreException e) { |
| throw new AssertionFailedError(e.toString()); |
| } |
| |
| // should parse correctly first before we look at the bindings |
| if (options.checkSyntaxProblems) { |
| |
| // this should work for C++ also, CVisitor.getProblems() and CPPVisitor.getProblems() are exactly the same code! |
| if (CVisitor.getProblems(tu).length != 0) { |
| throw new AssertionFailedError(" CVisitor has AST Problems "); |
| } |
| } |
| |
| if (options.checkPreprocessorProblems) { |
| if (tu.getPreprocessorProblems().length != 0) { |
| throw new AssertionFailedError(language.getName() + " TranslationUnit has Preprocessor Problems "); |
| } |
| } |
| |
| // resolve all bindings |
| if (options.checkBindings) { |
| NameResolver res = new NameResolver(); |
| tu.accept(res); |
| if (res.problemBindings.size() != options.expectedProblemBindings) |
| throw new AssertionFailedError("Expected " + options.expectedProblemBindings |
| + " problem(s), encountered " + res.problemBindings.size()); |
| |
| if (options.problems != null) { |
| for (int i = 0; i < options.problems.length; i++) { |
| String expected = options.problems[i]; |
| String actual = res.problemBindings.get(i); |
| if (!expected.equals(actual)) |
| throw new AssertionFailedError( |
| String.format("Problem binding not equal, expected: %s, got: %s", expected, actual)); |
| } |
| } |
| } |
| |
| return tu; |
| } |
| |
| /** |
| * TODO thats WAY too many parameters, need to use a parameter object, need to refactor the |
| * DOM parser test suite so that its a lot cleaner. |
| */ |
| public static IASTTranslationUnit parse(FileContent fileContent, ILanguage language, IScannerInfo scanInfo, |
| IncludeFileContentProvider fileContentProvider, Options options) { |
| testsRun++; |
| |
| IASTTranslationUnit tu; |
| try { |
| int languageOptions = 0; |
| if (options.limitTrivialInitializers >= 0 && options.limitTrivialInitializers != Integer.MAX_VALUE) |
| languageOptions |= ILanguage.OPTION_SKIP_TRIVIAL_EXPRESSIONS_IN_AGGREGATE_INITIALIZERS; |
| |
| tu = language.getASTTranslationUnit(fileContent, scanInfo, fileContentProvider, null, languageOptions, |
| ParserUtil.getParserLogService()); |
| } catch (CoreException e) { |
| throw new AssertionFailedError(e.toString()); |
| } |
| |
| // should parse correctly first before we look at the bindings |
| if (options.checkSyntaxProblems) { |
| |
| // this should work for C++ also, CVisitor.getProblems() and CPPVisitor.getProblems() are exactly the same code! |
| if (CVisitor.getProblems(tu).length != 0) { |
| throw new AssertionFailedError(" CVisitor has AST Problems "); |
| } |
| } |
| |
| if (options.checkPreprocessorProblems) { |
| if (tu.getPreprocessorProblems().length != 0) { |
| throw new AssertionFailedError(language.getName() + " TranslationUnit has Preprocessor Problems "); |
| } |
| } |
| |
| // resolve all bindings |
| if (options.checkBindings) { |
| NameResolver res = new NameResolver(); |
| tu.accept(res); |
| if (res.problemBindings.size() != options.expectedProblemBindings) |
| throw new AssertionFailedError("Expected " + options.expectedProblemBindings |
| + " problem(s), encountered " + res.problemBindings.size()); |
| |
| if (options.problems != null) { |
| for (int i = 0; i < options.problems.length; i++) { |
| String expected = options.problems[i]; |
| String actual = res.problemBindings.get(i); |
| if (!expected.equals(actual)) |
| throw new AssertionFailedError( |
| String.format("Problem binding not equal, expected: %s, got: %s", expected, actual)); |
| } |
| } |
| } |
| |
| return tu; |
| } |
| |
| public static IASTTranslationUnit commentParse(String code, ILanguage language) { |
| |
| IASTTranslationUnit tu; |
| try { |
| tu = language.getASTTranslationUnit(FileContent.create(AST2TestBase.TEST_CODE, code.toCharArray()), |
| new ScannerInfo(), null, null, ILanguage.OPTION_ADD_COMMENTS, ParserUtil.getParserLogService()); |
| } catch (CoreException e) { |
| throw new AssertionFailedError(e.toString()); |
| } |
| return tu; |
| } |
| |
| public static IASTCompletionNode getCompletionNode(String code, ILanguage lang) { |
| int offset = code.length(); |
| if (offset > 0 && '\n' == code.charAt(offset - 1)) { |
| offset--; |
| } |
| return getCompletionNode(code, lang, offset); |
| } |
| |
| public static IASTCompletionNode getCompletionNode(String code, ILanguage language, int offset) { |
| |
| try { |
| return language.getCompletionNode(FileContent.create(AST2TestBase.TEST_CODE, code.toCharArray()), |
| new ScannerInfo(), null, null, ParserUtil.getParserLogService(), offset); |
| } catch (CoreException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| } |