1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 14:42:11 +02:00

Bug 292229 - Consider files with other extensions for inclusion proposals

Proposals where the extension is not a known C/C++ header file extension
are ranked below proposals where the extension is one.

Proposals where the extension is a known C/C++ *source* file extension,
and proposals where the filename begins with a '.', are still not considered.

Change-Id: I80784f8f15a01b05977a288affbe3958f1400bdf
This commit is contained in:
Nathan Ridge 2017-01-17 21:55:05 -05:00
parent c5f3bbb55a
commit 3c20d6f0ea
6 changed files with 92 additions and 30 deletions

View file

@ -65,6 +65,7 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
protected final static int IS_TEMPLATE = 0x02;
protected final static int FILTER_RESULTS = 0x04;
protected final static int ALLOW_EXTRA_RESULTS = 0x08;
protected final static int CHECK_ORDER = 0x10;
protected final static int DEFAULT_FLAGS = FILTER_RESULTS;
@ -171,12 +172,15 @@ public abstract class AbstractContentAssistTest extends BaseUITestCase {
boolean isTemplate = (flags & IS_TEMPLATE) != 0;
boolean filterResults = (flags & FILTER_RESULTS) != 0;
boolean allowExtraResults = (flags & ALLOW_EXTRA_RESULTS) != 0;
boolean checkOrder = (flags & CHECK_ORDER) != 0;
ContentAssistResult r = invokeContentAssist(offset, length, isCompletion, isTemplate, filterResults);
String[] resultStrings= toStringArray(r.results, compareType);
Arrays.sort(expected);
Arrays.sort(resultStrings);
if (!checkOrder) {
Arrays.sort(expected);
Arrays.sort(resultStrings);
}
if (CTestPlugin.getDefault().isDebugging()) {
System.out.println("Time: " + (r.endTime - r.startTime) + " ms");

View file

@ -54,10 +54,18 @@ public class CompletionTestBase extends AbstractContentAssistTest {
assertContentAssistResults(offset, expected, DEFAULT_FLAGS | ALLOW_EXTRA_RESULTS, compareType);
}
protected void assertOrderedCompletionResults(int offset, String[] expected, CompareType compareType) throws Exception {
assertContentAssistResults(offset, expected, DEFAULT_FLAGS | CHECK_ORDER, compareType);
}
protected void assertCompletionResults(String[] expected) throws Exception {
assertCompletionResults(fCursorOffset, expected, REPLACEMENT);
}
protected void assertOrderedCompletionResults(String[] expected) throws Exception {
assertOrderedCompletionResults(fCursorOffset, expected, REPLACEMENT);
}
protected void assertParameterHint(String[] expected) throws Exception {
assertContentAssistResults(fCursorOffset, expected, AbstractContentAssistTest.DEFAULT_FLAGS, CONTEXT);
}

View file

@ -909,6 +909,29 @@ public class CompletionTests extends CompletionTestBase {
}
}
//#include "/*cursor*/
public void testHeaderFileWithNoExtension_292229() throws Exception {
File tempRoot= new File(System.getProperty("java.io.tmpdir"));
File tempDir= new File(tempRoot, "cdttest_292229");
tempDir.mkdir();
try {
createIncludeFiles(tempDir, new String[] {
"h1/bar",
"h1/foo.hpp"
});
// A file like h1/bar which is not known to be a header should appear
// in the proposal list, but below files that are known to be headers
// like h1/foo.hpp.
String[] expected = {
"\"foo.hpp\"",
"\"bar\""
};
assertOrderedCompletionResults(expected);
} finally {
deleteDir(tempDir);
}
}
public static void deleteDir(File dir) {
File[] files = dir.listFiles();
for (File file : files) {

View file

@ -19,7 +19,6 @@ import org.eclipse.jface.text.templates.persistence.TemplateStore;
import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.tests.text.contentassist2.AbstractContentAssistTest.CompareType;
import org.eclipse.cdt.internal.corext.template.c.CContextType;

View file

@ -125,6 +125,16 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
return false;
}
private static class PotentialInclude {
public String fPath;
public boolean fKnownContentType; // true for directories and files known to be headers
public PotentialInclude(String path, boolean knownContentType) {
fPath = path;
fKnownContentType = knownContentType;
}
}
private void addInclusionProposals(CContentAssistInvocationContext context, List<ICompletionProposal> proposals) throws Exception {
if (context.isContextInformationStyle()) {
return;
@ -141,7 +151,7 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
prefix= prefix.substring(1);
}
IPath prefixPath= new Path(prefix);
String[] potentialIncludes= collectIncludeFiles(tu, prefixPath, angleBrackets);
PotentialInclude[] potentialIncludes= collectIncludeFiles(tu, prefixPath, angleBrackets);
if (potentialIncludes.length > 0) {
IInclude[] includes= tu.getIncludes();
Set<String> alreadyIncluded= new HashSet<String>();
@ -149,11 +159,11 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
alreadyIncluded.add(includeDirective.getElementName());
}
Image image = getImage(CElementImageProvider.getIncludeImageDescriptor());
for (String include : potentialIncludes) {
if (alreadyIncluded.add(include)) {
for (PotentialInclude include : potentialIncludes) {
if (alreadyIncluded.add(include.fPath)) {
final char openingBracket= angleBrackets ? '<' : '"';
final char closingBracket= angleBrackets ? '>' : '"';
String repString= openingBracket + include;
String repString= openingBracket + include.fPath;
final String dispString= repString + closingBracket;
int repLength = prefix.length() + 1;
int repOffset= context.getInvocationOffset() - repLength;
@ -161,7 +171,7 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
if (needClosingBracket) {
repString += closingBracket;
}
final boolean isDir= include.endsWith("/"); //$NON-NLS-1$
final boolean isDir= include.fPath.endsWith("/"); //$NON-NLS-1$
final int relevance= computeRelevance(prefix, include) + (isDir ? 0 : 1);
final CCompletionProposal proposal= createProposal(repOffset, repLength, repString, dispString, image, relevance, context);
if (!isDir && !needClosingBracket) {
@ -183,8 +193,8 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
* @return an array of incude file names
* @throws CoreException
*/
private String[] collectIncludeFiles(final ITranslationUnit tu, IPath prefixPath, boolean angleBrackets) throws CoreException {
final List<String> includeFiles= new ArrayList<String>();
private PotentialInclude[] collectIncludeFiles(final ITranslationUnit tu, IPath prefixPath, boolean angleBrackets) throws CoreException {
final List<PotentialInclude> includeFiles= new ArrayList<>();
if (!angleBrackets) {
// search in current directory
IResource resource= tu.getResource();
@ -202,7 +212,7 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
if (info != null) {
collectIncludeFilesFromScannerInfo(tu, info, prefixPath, angleBrackets, includeFiles);
}
return includeFiles.toArray(new String[includeFiles.size()]);
return includeFiles.toArray(new PotentialInclude[includeFiles.size()]);
}
/**
@ -212,7 +222,8 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
* @param angleBrackets whether angle brackets enclose the include file name
* @param includeFiles the result list
*/
private void collectIncludeFilesFromScannerInfo(ITranslationUnit tu, IScannerInfo info, IPath prefixPath, boolean angleBrackets, List<String> includeFiles) {
private void collectIncludeFilesFromScannerInfo(ITranslationUnit tu, IScannerInfo info, IPath prefixPath,
boolean angleBrackets, List<PotentialInclude> includeFiles) {
if (!angleBrackets && info instanceof IExtendedScannerInfo) {
IExtendedScannerInfo extendedInfo= (IExtendedScannerInfo) info;
String[] quoteIncludes= extendedInfo.getLocalIncludePath();
@ -240,7 +251,8 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
* @param prefixPath the path part to match the sub-directory and file name
* @param includeFiles the result list
*/
private void collectIncludeFilesFromDirectory(ITranslationUnit tu, IPath directory, IPath prefixPath, List<String> includeFiles) {
private void collectIncludeFilesFromDirectory(ITranslationUnit tu, IPath directory, IPath prefixPath,
List<PotentialInclude> includeFiles) {
final String namePrefix;
if (prefixPath.segmentCount() == 0) {
namePrefix= ""; //$NON-NLS-1$
@ -269,17 +281,28 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
for (File file : files) {
final String name= file.getName();
if (name.length() >= prefixLength && matcher.match(name.toCharArray())) {
if (file.isFile()) {
if (CoreModel.isValidCXXHeaderUnitName(project, name) || CoreModel.isValidCHeaderUnitName(project, name)) {
includeFiles.add(prefixPath.append(name).toString());
}
} else if (file.isDirectory()) {
includeFiles.add(prefixPath.append(name).addTrailingSeparator().toString());
}
maybeAddInclude(prefixPath, includeFiles, project, file.isFile(), file.isDirectory(), name);
}
}
}
private static void maybeAddInclude(IPath prefixPath, List<PotentialInclude> includeFiles,
final IProject project, boolean isFile, boolean isDirectory, final String name) {
if (isFile) {
boolean definitelyHeader = CoreModel.isValidHeaderUnitName(project, name);
boolean definitelyNotHeader = false;
if (!definitelyHeader) {
definitelyNotHeader = CoreModel.isValidSourceUnitName(project, name) || name.startsWith("."); //$NON-NLS-1$
}
if (definitelyHeader || !definitelyNotHeader) {
includeFiles.add(new PotentialInclude(prefixPath.append(name).toString(), definitelyHeader));
}
} else if (isDirectory) {
includeFiles.add(new PotentialInclude(
prefixPath.append(name).addTrailingSeparator().toString(), true));
}
}
/**
* Collect include files from the given resource container.
*
@ -289,7 +312,8 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
* @param includeFiles the result list
* @throws CoreException
*/
private void collectIncludeFilesFromContainer(final ITranslationUnit tu, IContainer parent, IPath prefixPath, final List<String> includeFiles) throws CoreException {
private void collectIncludeFilesFromContainer(final ITranslationUnit tu, IContainer parent,
IPath prefixPath, final List<PotentialInclude> includeFiles) throws CoreException {
final String namePrefix;
if (prefixPath.segmentCount() == 0) {
namePrefix= ""; //$NON-NLS-1$
@ -328,13 +352,8 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
return true;
}
if (name.length() >= prefixLength && matcher.match(name.toCharArray())) {
if (type == IResource.FILE) {
if (CoreModel.isValidCXXHeaderUnitName(project, name) || CoreModel.isValidCHeaderUnitName(project, name)) {
includeFiles.add(cPrefixPath.append(name).toString());
}
} else if (type == IResource.FOLDER) {
includeFiles.add(cPrefixPath.append(name).addTrailingSeparator().toString());
}
maybeAddInclude(cPrefixPath, includeFiles, project, type == IResource.FILE,
type == IResource.FOLDER, name);
}
return false;
}}, IResource.DEPTH_ONE);
@ -369,12 +388,15 @@ public class InclusionProposalComputer implements ICompletionProposalComputer {
* @param match the matching identifier
* @return a relevance value inidicating the quality of the name match
*/
protected int computeRelevance(String prefix, String match) {
protected int computeRelevance(String prefix, PotentialInclude match) {
int baseRelevance= 0;
boolean caseMatch= prefix.length() > 0 && match.startsWith(prefix);
boolean caseMatch= prefix.length() > 0 && match.fPath.startsWith(prefix);
if (caseMatch) {
baseRelevance += RelevanceConstants.CASE_MATCH_RELEVANCE;
}
if (match.fKnownContentType) {
baseRelevance += RelevanceConstants.FILE_TYPE_RELEVANCE;
}
return baseRelevance;
}

View file

@ -12,6 +12,12 @@
package org.eclipse.cdt.internal.ui.text.contentassist;
public interface RelevanceConstants {
/**
* For inclusion proposals only, relevance increment for matches
* with a file type known to be a header file.
*/
final int FILE_TYPE_RELEVANCE = 2000;
/** Relevance increment for same case matches */
final int CASE_MATCH_RELEVANCE = 1000;