mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-23 17:05:26 +02:00
Configuring framework search, bug 69529.
This commit is contained in:
parent
24b07e23d7
commit
031bf4556a
7 changed files with 204 additions and 63 deletions
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2004, 2008 IBM Corporation and others.
|
||||
* Copyright (c) 2004, 2009 IBM Corporation 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
|
||||
|
@ -49,6 +49,7 @@ public class InclusionTests extends PreprocessorTestsBase {
|
|||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
if (fProject != null) {
|
||||
CProjectHelper.delete(fProject);
|
||||
|
@ -77,6 +78,36 @@ public class InclusionTests extends PreprocessorTestsBase {
|
|||
return folder;
|
||||
}
|
||||
|
||||
// #include "one.h"
|
||||
// #include "f1/two.h"
|
||||
// #include "f1/f2/three.h"
|
||||
public void testIncludeVariables() throws Exception {
|
||||
String content= getAboveComment();
|
||||
|
||||
IFolder f0 = importFolder(".framework");
|
||||
importFolder("f1.framework");
|
||||
importFolder("f1");
|
||||
importFolder("f1/f2.framework");
|
||||
importFolder("f3");
|
||||
IFile base = importFile("base.cpp", content);
|
||||
|
||||
importFile(".framework/one.h", "1");
|
||||
importFile("f1.framework/two.h", "2");
|
||||
importFile("f1/f2.framework/three.h", "3");
|
||||
|
||||
String[] path = {
|
||||
f0.getLocation().removeLastSegments(1) + "/__framework__.framework/__filename__"
|
||||
};
|
||||
IScannerInfo scannerInfo = new ExtendedScannerInfo(Collections.EMPTY_MAP, path, new String[]{}, null);
|
||||
CodeReader reader= new CodeReader(base.getLocation().toString());
|
||||
initializeScanner(reader, ParserLanguage.C, ParserMode.COMPLETE_PARSE, scannerInfo);
|
||||
|
||||
// first file is not picked up (no framework)
|
||||
validateInteger("2");
|
||||
// third file is not picked up (framework must be a single folder)
|
||||
validateEOF();
|
||||
}
|
||||
|
||||
public void testIncludeNext() throws Exception {
|
||||
String baseFile = "int zero; \n#include \"foo.h\""; //$NON-NLS-1$
|
||||
String i1Next = "int one; \n#include_next <bar/foo.h>"; //$NON-NLS-1$
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007, 2008 Wind River Systems, Inc. and others.
|
||||
* Copyright (c) 2007, 2009 Wind River Systems, Inc. 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
|
||||
|
@ -88,9 +88,17 @@ public abstract class PreprocessorTestsBase extends BaseTestCase {
|
|||
}
|
||||
|
||||
protected void initializeScanner() throws Exception {
|
||||
initializeScanner(getAboveComment());
|
||||
}
|
||||
|
||||
protected StringBuffer[] getTestContent(int sections) throws IOException {
|
||||
StringBuffer[] input= TestSourceReader.getContentsForTest(
|
||||
CTestPlugin.getDefault().getBundle(), "parser", getClass(), getName(), 1);
|
||||
initializeScanner(input[0].toString());
|
||||
CTestPlugin.getDefault().getBundle(), "parser", getClass(), getName(), sections);
|
||||
return input;
|
||||
}
|
||||
|
||||
protected String getAboveComment() throws IOException {
|
||||
return getTestContent(1)[0].toString();
|
||||
}
|
||||
|
||||
protected void fullyTokenize() throws Exception {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2002, 2008 IBM Corporation and others.
|
||||
* Copyright (c) 2002, 2009 IBM Corporation 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
|
||||
|
@ -30,6 +30,15 @@ public interface IScannerInfo {
|
|||
/**
|
||||
* Returns an array of paths that are searched when processing an include directive.
|
||||
* see {@link IExtendedScannerInfo#getLocalIncludePath()}
|
||||
*
|
||||
* In order to handle framework includes used on Apple Computers you can make use of
|
||||
* the two variables: '__framework__' and '__filename__'.
|
||||
* <br> E.g.: /System/Library/Frameworks/__framework__.framework/Headers/__filename__,
|
||||
* /System/Library/Frameworks/__framework__.framework/PrivateHeaders/__filename__
|
||||
* would handle the framework search for '/System/Library/Frameworks'
|
||||
*
|
||||
* The variables are handled only, if a search path element makes use of both of the variables.
|
||||
* Such a search path element is not used for directives that are not of the form 'folder/name'.
|
||||
*/
|
||||
public String[] getIncludePaths();
|
||||
}
|
||||
|
|
|
@ -74,7 +74,6 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
|
||||
private static final char[] EMPTY_CHAR_ARRAY = new char[0];
|
||||
private static final char[] ONE = "1".toCharArray(); //$NON-NLS-1$
|
||||
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
|
||||
|
||||
|
||||
// standard built-ins
|
||||
|
@ -96,15 +95,15 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
private static final Token END_OF_INPUT = new Token(IToken.tEND_OF_INPUT, null, 0, 0);
|
||||
|
||||
private interface IIncludeFileTester<T> {
|
||||
T checkFile(String path, String fileName, boolean isHeuristicMatch);
|
||||
T checkFile(String path, boolean isHeuristicMatch, IncludeSearchPathElement onPath);
|
||||
}
|
||||
|
||||
final private IIncludeFileTester<IncludeFileContent> createCodeReaderTester= new IIncludeFileTester<IncludeFileContent>() {
|
||||
public IncludeFileContent checkFile(String path, String fileName, boolean isHeuristicMatch) {
|
||||
final String finalPath = ScannerUtility.createReconciledPath(path, fileName);
|
||||
final IncludeFileContent fc= fCodeReaderFactory.getContentForInclusion(finalPath);
|
||||
final private IIncludeFileTester<IncludeFileContent> createCodeReaderTester= new IIncludeFileTester<IncludeFileContent>() {
|
||||
public IncludeFileContent checkFile(String path, boolean isHeuristicMatch, IncludeSearchPathElement onPath) {
|
||||
final IncludeFileContent fc= fCodeReaderFactory.getContentForInclusion(path);
|
||||
if (fc != null) {
|
||||
fc.setFoundByHeuristics(isHeuristicMatch);
|
||||
fc.setFoundOnPath(onPath);
|
||||
}
|
||||
return fc;
|
||||
}
|
||||
|
@ -112,12 +111,11 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
|
||||
private static class IncludeResolution {String fLocation; boolean fHeuristic;}
|
||||
final private IIncludeFileTester<IncludeResolution> createPathTester= new IIncludeFileTester<IncludeResolution>() {
|
||||
public IncludeResolution checkFile(String path, String fileName, boolean isHeuristicMatch) {
|
||||
String finalPath= ScannerUtility.createReconciledPath(path, fileName);
|
||||
if (fCodeReaderFactory.getInclusionExists(finalPath)) {
|
||||
public IncludeResolution checkFile(String path, boolean isHeuristicMatch, IncludeSearchPathElement onPath) {
|
||||
if (fCodeReaderFactory.getInclusionExists(path)) {
|
||||
IncludeResolution res= new IncludeResolution();
|
||||
res.fHeuristic= isHeuristicMatch;
|
||||
res.fLocation= finalPath;
|
||||
res.fLocation= path;
|
||||
return res;
|
||||
}
|
||||
return null;
|
||||
|
@ -168,8 +166,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
final private char[] fAdditionalNumericLiteralSuffixes;
|
||||
final private CharArrayIntMap fKeywords;
|
||||
final private CharArrayIntMap fPPKeywords;
|
||||
final private String[] fIncludePaths;
|
||||
final private String[] fQuoteIncludePaths;
|
||||
private IncludeSearchPathElement[] fIncludeSearchPath;
|
||||
private String[][] fPreIncludedFiles= null;
|
||||
|
||||
private int fContentAssistLimit= -1;
|
||||
|
@ -206,9 +203,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
fKeywords= new CharArrayIntMap(40, -1);
|
||||
fPPKeywords= new CharArrayIntMap(40, -1);
|
||||
configureKeywords(language, configuration);
|
||||
|
||||
fIncludePaths= info.getIncludePaths();
|
||||
fQuoteIncludePaths= getQuoteIncludePath(info);
|
||||
configureIncludeSearchPath(info);
|
||||
|
||||
fExpressionEvaluator= new ExpressionEvaluator();
|
||||
fMacroDefinitionParser= new MacroDefinitionParser();
|
||||
|
@ -318,18 +313,25 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
return array == null ? EMPTY_CHAR_ARRAY : array;
|
||||
}
|
||||
|
||||
private String[] getQuoteIncludePath(IScannerInfo info) {
|
||||
private void configureIncludeSearchPath(IScannerInfo info) {
|
||||
String[] searchPath= info.getIncludePaths();
|
||||
int idx= 0;
|
||||
if (info instanceof IExtendedScannerInfo) {
|
||||
final IExtendedScannerInfo einfo= (IExtendedScannerInfo) info;
|
||||
final String[] qip= einfo.getLocalIncludePath();
|
||||
if (qip != null && qip.length > 0) {
|
||||
final String[] result= new String[qip.length + fIncludePaths.length];
|
||||
System.arraycopy(qip, 0, result, 0, qip.length);
|
||||
System.arraycopy(fIncludePaths, 0, result, qip.length, fIncludePaths.length);
|
||||
return result;
|
||||
}
|
||||
final String[] quoteIncludeSearchPath= einfo.getLocalIncludePath();
|
||||
if (quoteIncludeSearchPath != null && quoteIncludeSearchPath.length > 0) {
|
||||
fIncludeSearchPath= new IncludeSearchPathElement[quoteIncludeSearchPath.length + searchPath.length];
|
||||
for (String qip : quoteIncludeSearchPath) {
|
||||
fIncludeSearchPath[idx++]= new IncludeSearchPathElement(qip, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return info.getIncludePaths();
|
||||
if (fIncludeSearchPath == null) {
|
||||
fIncludeSearchPath= new IncludeSearchPathElement[searchPath.length];
|
||||
}
|
||||
for (String path : searchPath) {
|
||||
fIncludeSearchPath[idx++]= new IncludeSearchPathElement(path, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupMacroDictionary(IScannerExtensionConfiguration config, IScannerInfo info, ParserLanguage lang) {
|
||||
|
@ -872,20 +874,20 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
}
|
||||
}
|
||||
|
||||
private <T> T findInclusion(final String filename, final boolean quoteInclude,
|
||||
private <T> T findInclusion(final String includeDirective, final boolean quoteInclude,
|
||||
final boolean includeNext, final String currentFile, final IIncludeFileTester<T> tester) {
|
||||
T reader = null;
|
||||
// filename is an absolute path or it is a Linux absolute path on a windows machine
|
||||
if (new File(filename).isAbsolute() || filename.startsWith("/")) { //$NON-NLS-1$
|
||||
return tester.checkFile(EMPTY_STRING, filename, false);
|
||||
if (new File(includeDirective).isAbsolute() || includeDirective.startsWith("/")) { //$NON-NLS-1$
|
||||
return tester.checkFile(includeDirective, false, null);
|
||||
}
|
||||
|
||||
if (currentFile != null && quoteInclude && !includeNext) {
|
||||
// Check to see if we find a match in the current directory
|
||||
final File currentDir= new File(currentFile).getParentFile();
|
||||
if (currentDir != null) {
|
||||
String absolutePath = currentDir.getAbsolutePath();
|
||||
reader = tester.checkFile(absolutePath, filename, false);
|
||||
final String fileLocation = ScannerUtility.createReconciledPath(currentDir.getAbsolutePath(), includeDirective);
|
||||
reader = tester.checkFile(fileLocation, false, null);
|
||||
if (reader != null) {
|
||||
return reader;
|
||||
}
|
||||
|
@ -894,43 +896,31 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
|
||||
// if we're not include_next, then we are looking for the first occurrence of
|
||||
// the file, otherwise, we ignore all the paths before the current directory
|
||||
final String[] isp= quoteInclude ? fQuoteIncludePaths : fIncludePaths;
|
||||
if (isp != null) {
|
||||
int i=0;
|
||||
if (includeNext && currentFile != null) {
|
||||
final File currentDir= new File(currentFile).getParentFile();
|
||||
if (currentDir != null) {
|
||||
i= findIncludePos(isp, currentDir) + 1;
|
||||
IncludeSearchPathElement searchAfter= includeNext ? fCurrentContext.getFoundOnPath() : null;
|
||||
for (IncludeSearchPathElement path : fIncludeSearchPath) {
|
||||
if (searchAfter != null) {
|
||||
if (searchAfter.equals(path)) {
|
||||
searchAfter= null;
|
||||
}
|
||||
}
|
||||
for (; i < isp.length; ++i) {
|
||||
reader= tester.checkFile(isp[i], filename, false);
|
||||
if (reader != null) {
|
||||
return reader;
|
||||
} else if (quoteInclude || !path.isForQuoteIncludesOnly()) {
|
||||
String fileLocation = path.getLocation(includeDirective);
|
||||
if (fileLocation != null) {
|
||||
reader= tester.checkFile(fileLocation, false, path);
|
||||
if (reader != null) {
|
||||
return reader;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fIncludeFileResolutionHeuristics != null) {
|
||||
String location= fIncludeFileResolutionHeuristics.findInclusion(filename, currentFile);
|
||||
String location= fIncludeFileResolutionHeuristics.findInclusion(includeDirective, currentFile);
|
||||
if (location != null) {
|
||||
return tester.checkFile(null, location, true);
|
||||
return tester.checkFile(location, true, null);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int findIncludePos(String[] paths, File currentDirectory) {
|
||||
for (; currentDirectory != null; currentDirectory = currentDirectory.getParentFile()) {
|
||||
for (int i = 0; i < paths.length; ++i) {
|
||||
File pathDir = new File(paths[i]);
|
||||
if (currentDirectory.equals(pathDir))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer("Scanner @ file:"); //$NON-NLS-1$
|
||||
|
@ -1191,6 +1181,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
fAllIncludedFiles.add(path);
|
||||
ILocationCtx ctx= fLocationMap.pushInclusion(poundOffset, nameOffsets[0], nameOffsets[1], condEndOffset, reader.buffer, path, headerName, userInclude, isHeuristic, fi.isSource());
|
||||
ScannerContext fctx= new ScannerContext(ctx, fCurrentContext, new Lexer(reader.buffer, fLexOptions, this, this));
|
||||
fctx.setFoundOnPath(fi.getFoundOnPath());
|
||||
fCurrentContext= fctx;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -46,6 +46,7 @@ public class IncludeFileContent {
|
|||
private boolean fHeuristic;
|
||||
private boolean fIsSource= false;
|
||||
private List<IIndexFile> fFiles;
|
||||
private IncludeSearchPathElement fFoundOnPath;
|
||||
|
||||
/**
|
||||
* For skipping include files.
|
||||
|
@ -165,4 +166,12 @@ public class IncludeFileContent {
|
|||
public void setIsSource(boolean isSource) {
|
||||
fIsSource= isSource;
|
||||
}
|
||||
|
||||
public IncludeSearchPathElement getFoundOnPath() {
|
||||
return fFoundOnPath;
|
||||
}
|
||||
|
||||
public void setFoundOnPath(IncludeSearchPathElement isp) {
|
||||
fFoundOnPath= isp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Wind River Systems, Inc. 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:
|
||||
* Markus Schorn - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.parser.scanner;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Represents an entry of the include search path
|
||||
*/
|
||||
final class IncludeSearchPathElement {
|
||||
private static final boolean NON_SLASH_SEPARATOR = File.separatorChar != '/';
|
||||
public static final String FRAMEWORK_VAR = "__framework__"; //$NON-NLS-1$
|
||||
public static final String FILE_VAR = "__filename__"; //$NON-NLS-1$
|
||||
|
||||
|
||||
private final String fPath;
|
||||
private final boolean fForQuoteIncludesOnly;
|
||||
private final boolean fIsFrameworkDirectory;
|
||||
|
||||
IncludeSearchPathElement(String path, boolean forQuoteIncludesOnly) {
|
||||
fPath= path;
|
||||
fForQuoteIncludesOnly= forQuoteIncludesOnly;
|
||||
|
||||
if (path.indexOf('_') != -1 && path.indexOf(FRAMEWORK_VAR) != -1 && path.indexOf(FILE_VAR) != -1) {
|
||||
fIsFrameworkDirectory= true;
|
||||
} else {
|
||||
fIsFrameworkDirectory= false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isForQuoteIncludesOnly() {
|
||||
return fForQuoteIncludesOnly;
|
||||
}
|
||||
|
||||
public String getLocation(String includeDirective) {
|
||||
if (fIsFrameworkDirectory) {
|
||||
int lastSep = lastSeparator(includeDirective);
|
||||
if (lastSep < 0) {
|
||||
return null;
|
||||
}
|
||||
String framework = includeDirective.substring(0, lastSep);
|
||||
if (lastSeparator(framework) != -1 || framework.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String file= includeDirective.substring(lastSep+1);
|
||||
if (file.length() == 0)
|
||||
return null;
|
||||
|
||||
StringBuilder buf= new StringBuilder(fPath);
|
||||
replaceAll(buf, FRAMEWORK_VAR, framework);
|
||||
replaceAll(buf, FILE_VAR, file);
|
||||
return ScannerUtility.reconcilePath(buf.toString());
|
||||
}
|
||||
return ScannerUtility.createReconciledPath(fPath, includeDirective);
|
||||
}
|
||||
|
||||
private int lastSeparator(String path) {
|
||||
int lastSep= path.lastIndexOf('/');
|
||||
if (NON_SLASH_SEPARATOR) {
|
||||
lastSep= Math.max(lastSep, path.lastIndexOf(File.separatorChar));
|
||||
}
|
||||
return lastSep;
|
||||
}
|
||||
|
||||
private void replaceAll(StringBuilder buf, String find, final String replace) {
|
||||
for (int idx= buf.indexOf(find); idx > 0; idx= buf.indexOf(find, idx)) {
|
||||
buf.replace(idx, idx+find.length(), replace);
|
||||
idx+= replace.length();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,6 +44,7 @@ final class ScannerContext {
|
|||
private Token fTokens;
|
||||
private ArrayList<Conditional> fConditionals= null;
|
||||
private CodeState fCurrentState= CodeState.eActive;
|
||||
private IncludeSearchPathElement fFoundOnPath;
|
||||
|
||||
/**
|
||||
* @param ctx
|
||||
|
@ -56,9 +57,7 @@ final class ScannerContext {
|
|||
}
|
||||
|
||||
public ScannerContext(ILocationCtx ctx, ScannerContext parent, TokenList tokens) {
|
||||
fLocationCtx= ctx;
|
||||
fParent= parent;
|
||||
fLexer= null;
|
||||
this (ctx, parent, (Lexer) null);
|
||||
fTokens= tokens.first();
|
||||
fInactiveState= CodeState.eSkipInactive; // no branches in result of macro expansion
|
||||
}
|
||||
|
@ -270,4 +269,18 @@ final class ScannerContext {
|
|||
return 0;
|
||||
return fConditionals.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element of the include search path that was used to find this context, or <code>null</code> if not applicable.
|
||||
*/
|
||||
public IncludeSearchPathElement getFoundOnPath() {
|
||||
return fFoundOnPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element of the include search path that was used to find this context, or <code>null</code> if not applicable.
|
||||
*/
|
||||
public void setFoundOnPath(IncludeSearchPathElement foundOnPath) {
|
||||
fFoundOnPath= foundOnPath;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue