1
0
Fork 0
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:
Markus Schorn 2009-07-10 07:51:40 +00:00
parent 24b07e23d7
commit 031bf4556a
7 changed files with 204 additions and 63 deletions

View file

@ -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$

View file

@ -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 {

View file

@ -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();
}

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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();
}
}
}

View file

@ -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;
}
}